diff --git a/CMakeLists.txt b/CMakeLists.txt index c57b0cec3..25350186d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,17 +29,16 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) -set(REQUIRED_QT_VERSION "5.15.0") -set(KF5_MINIMUM_VERSION "5.101.0") -set(LXQT_GLOBALKEYS_MINIMUM_VERSION "1.4.0") -set(LXQT_MINIMUM_VERSION "1.4.0") - -find_package(Qt5DBus ${REQUIRED_QT_VERSION} REQUIRED) -find_package(Qt5LinguistTools ${REQUIRED_QT_VERSION} REQUIRED) -find_package(Qt5Widgets ${REQUIRED_QT_VERSION} REQUIRED) -find_package(Qt5X11Extras ${REQUIRED_QT_VERSION} REQUIRED) -find_package(Qt5Xml ${REQUIRED_QT_VERSION} REQUIRED) -find_package(KF5WindowSystem ${KF5_MINIMUM_VERSION} REQUIRED) +set(REQUIRED_QT_VERSION "6.6.0") +set(KF6_MINIMUM_VERSION "6.0.0") +set(LXQT_GLOBALKEYS_MINIMUM_VERSION "2.0.0") +set(LXQT_MINIMUM_VERSION "2.0.0") + +find_package(Qt6DBus ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6LinguistTools ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6Widgets ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6Xml ${REQUIRED_QT_VERSION} REQUIRED) +find_package(KF6WindowSystem ${KF6_MINIMUM_VERSION} REQUIRED) find_package(lxqt ${LXQT_MINIMUM_VERSION} REQUIRED) find_package(lxqt-globalkeys-ui ${LXQT_GLOBALKEYS_MINIMUM_VERSION} REQUIRED) find_package(lxqt-menu-data ${LXQT_MINIMUM_VERSION} REQUIRED) diff --git a/README.md b/README.md index 237192ac3..69b514706 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ As indicated by the name, a volume control. Technically Alsa, OSS and PulseAudio ### Compiling source code -The runtime dependencies are libxcomposite, libdbusmenu-qt5, KGuiAddons, KWindowSystem, Solid, menu-cache, [lxqt-menu-data](https://github.com/lxqt/lxqt-menu-data), [liblxqt](https://github.com/lxqt/liblxqt) and [lxqt-globalkeys](https://github.com/lxqt/lxqt-globalkeys). +The runtime dependencies are libxcomposite, libdbusmenu-lxqt, KGuiAddons, KWindowSystem, Solid, menu-cache, [lxqt-menu-data](https://github.com/lxqt/lxqt-menu-data), [liblxqt](https://github.com/lxqt/liblxqt) and [lxqt-globalkeys](https://github.com/lxqt/lxqt-globalkeys). Several plugins or features thereof are optional and need additional runtime dependencies. Namely these are (plugin / feature in parenthesis) Alsa library (Alsa support in plugin-volume), PulseAudio client library (PulseAudio support in plugin-volume), lm-sensors (plugin-sensors), libstatgrab (plugin-cpuload, plugin-networkmonitor), [libsysstat](https://github.com/lxqt/libsysstat) (plugin-sysstat). All of them are enabled by default and have to be disabled by CMake variables as required, see below. In addition CMake and [lxqt-build-tools](https://github.com/lxqt/lxqt-build-tools) are mandatory build dependencies. Git is optionally needed to pull latest VCS checkouts. diff --git a/cmake/BuildPlugin.cmake b/cmake/BuildPlugin.cmake index 0dd0d23f0..6c8ca2f66 100644 --- a/cmake/BuildPlugin.cmake +++ b/cmake/BuildPlugin.cmake @@ -36,12 +36,12 @@ MACRO (BUILD_LXQT_PLUGIN NAME) set (PLUGIN_DIR ${CMAKE_INSTALL_FULL_LIBDIR}/${PROGRAM}) endif (NOT DEFINED PLUGIN_DIR) - set(QTX_LIBRARIES Qt5::Widgets) + set(QTX_LIBRARIES Qt6::Widgets) if(QT_USE_QTXML) - set(QTX_LIBRARIES ${QTX_LIBRARIES} Qt5::Xml) + set(QTX_LIBRARIES ${QTX_LIBRARIES} Qt6::Xml) endif() if(QT_USE_QTDBUS) - set(QTX_LIBRARIES ${QTX_LIBRARIES} Qt5::DBus) + set(QTX_LIBRARIES ${QTX_LIBRARIES} Qt6::DBus) endif() list(FIND STATIC_PLUGINS ${NAME} IS_STATIC) @@ -52,7 +52,7 @@ MACRO (BUILD_LXQT_PLUGIN NAME) else() # static add_library(${NAME} STATIC ${SRC}) # build statically linked lib endif() - target_link_libraries(${NAME} ${QTX_LIBRARIES} lxqt ${LIBRARIES} KF5::WindowSystem) + target_link_libraries(${NAME} ${QTX_LIBRARIES} lxqt ${LIBRARIES} KF6::WindowSystem) install(FILES ${CONFIG_FILES} DESTINATION ${PLUGIN_SHARE_DIR}) install(FILES ${DESKTOP_FILES} DESTINATION ${PROG_SHARE_DIR}) diff --git a/panel/CMakeLists.txt b/panel/CMakeLists.txt index 3ea78acf0..79f46497b 100644 --- a/panel/CMakeLists.txt +++ b/panel/CMakeLists.txt @@ -1,5 +1,8 @@ set(PROJECT lxqt-panel) +# TODO +add_subdirectory(backends) + set(PRIV_HEADERS panelpluginsmodel.h windownotifier.h @@ -18,6 +21,12 @@ set(PRIV_HEADERS config/configstyling.h config/configpluginswidget.h config/addplugindialog.h + + backends/ilxqttaskbarabstractbackend.h + backends/lxqttaskbartypes.h + + backends/lxqttaskbardummybackend.h + backends/xcb/lxqttaskbarbackend_x11.h ) # using LXQt namespace in the public headers. @@ -26,6 +35,9 @@ set(PUB_HEADERS pluginsettings.h ilxqtpanelplugin.h ilxqtpanel.h + + backends/ilxqttaskbarabstractbackend.h + backends/lxqttaskbartypes.h ) set(SOURCES @@ -45,6 +57,11 @@ set(SOURCES config/configstyling.cpp config/configpluginswidget.cpp config/addplugindialog.cpp + + backends/ilxqttaskbarabstractbackend.cpp + + backends/lxqttaskbardummybackend.cpp + backends/xcb/lxqttaskbarbackend_x11.cpp ) set(UI @@ -74,7 +91,7 @@ endif () project(${PROJECT}) -set(QTX_LIBRARIES Qt5::Widgets Qt5::Xml Qt5::DBus) +set(QTX_LIBRARIES Qt6::Widgets Qt6::Xml Qt6::DBus) # Translations lxqt_translate_ts(QM_FILES SOURCES @@ -102,7 +119,7 @@ add_executable(${PROJECT} target_link_libraries(${PROJECT} ${LIBRARIES} ${QTX_LIBRARIES} - KF5::WindowSystem + KF6::WindowSystem ${STATIC_PLUGINS} ) diff --git a/panel/backends/CMakeLists.txt b/panel/backends/CMakeLists.txt new file mode 100644 index 000000000..8f34a3c67 --- /dev/null +++ b/panel/backends/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(xcb) diff --git a/panel/backends/ilxqttaskbarabstractbackend.cpp b/panel/backends/ilxqttaskbarabstractbackend.cpp new file mode 100644 index 000000000..137728263 --- /dev/null +++ b/panel/backends/ilxqttaskbarabstractbackend.cpp @@ -0,0 +1,25 @@ +#include "../panel/backends/ilxqttaskbarabstractbackend.h" + + +ILXQtTaskbarAbstractBackend::ILXQtTaskbarAbstractBackend(QObject *parent) + : QObject(parent) +{ + +} + +void ILXQtTaskbarAbstractBackend::moveApplicationToPrevNextDesktop(WId windowId, bool next) +{ + int count = getWorkspacesCount(); + if (count <= 1) + return; + + int targetWorkspace = getWindowWorkspace(windowId) + (next ? 1 : -1); + + // Wrap around + if (targetWorkspace > count) + targetWorkspace = 1; //Ids are 1-based + else if (targetWorkspace < 1) + targetWorkspace = count; + + setWindowOnWorkspace(windowId, targetWorkspace); +} diff --git a/panel/backends/ilxqttaskbarabstractbackend.h b/panel/backends/ilxqttaskbarabstractbackend.h new file mode 100644 index 000000000..fe3368363 --- /dev/null +++ b/panel/backends/ilxqttaskbarabstractbackend.h @@ -0,0 +1,97 @@ +#ifndef ILXQTTASKBARABSTRACTBACKEND_H +#define ILXQTTASKBARABSTRACTBACKEND_H + +#include + +#include "lxqttaskbartypes.h" + +class QIcon; +class QScreen; + +class ILXQtTaskbarAbstractBackend : public QObject +{ + Q_OBJECT + +public: + explicit ILXQtTaskbarAbstractBackend(QObject *parent = nullptr); + + // Backend + virtual bool supportsAction(WId windowId, LXQtTaskBarBackendAction action) const = 0; + + // Windows + virtual bool reloadWindows() = 0; + + virtual QVector getCurrentWindows() const = 0; + + virtual QString getWindowTitle(WId windowId) const = 0; + + virtual bool applicationDemandsAttention(WId windowId) const = 0; + + virtual QIcon getApplicationIcon(WId windowId, int fallbackDevicePixels) const = 0; + + virtual QString getWindowClass(WId windowId) const = 0; + + virtual LXQtTaskBarWindowLayer getWindowLayer(WId windowId) const = 0; + virtual bool setWindowLayer(WId windowId, LXQtTaskBarWindowLayer layer) = 0; + + virtual LXQtTaskBarWindowState getWindowState(WId windowId) const = 0; + virtual bool setWindowState(WId windowId, LXQtTaskBarWindowState state, bool set = true) = 0; + + virtual bool isWindowActive(WId windowId) const = 0; + virtual bool raiseWindow(WId windowId, bool onCurrentWorkSpace) = 0; + + virtual bool closeWindow(WId windowId) = 0; + + virtual WId getActiveWindow() const = 0; + + // Workspaces + // NOTE: indexes are 1-based, 0 means "Show on All desktops" + virtual int getWorkspacesCount() const = 0; + virtual QString getWorkspaceName(int idx) const = 0; + + virtual int getCurrentWorkspace() const = 0; + virtual bool setCurrentWorkspace(int idx) = 0; + + virtual int getWindowWorkspace(WId windowId) const = 0; + virtual bool setWindowOnWorkspace(WId windowId, int idx) = 0; + + virtual void moveApplicationToPrevNextDesktop(WId windowId, bool next); // Default implementation + virtual void moveApplicationToPrevNextMonitor(WId windowId, bool next, bool raiseOnCurrentDesktop) = 0; + + virtual bool isWindowOnScreen(QScreen *screen, WId windowId) const = 0; + + // X11 Specific + virtual void moveApplication(WId windowId) = 0; + virtual void resizeApplication(WId windowId) = 0; + + virtual void refreshIconGeometry(WId windowId, const QRect &geom) = 0; + + // Panel internal + virtual bool isAreaOverlapped(const QRect& area) const = 0; + + // Show Destop TODO: split in multiple interfeces, this is becoming big + // NOTE: KWindowSystem already has these functions + // However on Wayland they are only compatible with KWin + // because internally it uses org_kde_plasma_window_management protocol + // We make this virtual so it can be implemented also for other compositors + virtual bool isShowingDesktop() const = 0; + virtual bool showDesktop(bool value) = 0; + +signals: + void reloaded(); + + // Windows + void windowAdded(WId windowId); + void windowRemoved(WId windowId); + void windowPropertyChanged(WId windowId, int prop); + + // Workspaces + void workspacesCountChanged(); + void workspaceNameChanged(int idx); + void currentWorkspaceChanged(int idx); + + // TODO: needed? + void activeWindowChanged(WId windowId); +}; + +#endif // ILXQTTASKBARABSTRACTBACKEND_H diff --git a/panel/backends/lxqttaskbardummybackend.cpp b/panel/backends/lxqttaskbardummybackend.cpp new file mode 100644 index 000000000..ceaf3c334 --- /dev/null +++ b/panel/backends/lxqttaskbardummybackend.cpp @@ -0,0 +1,166 @@ +#include "lxqttaskbardummybackend.h" + +#include + +LXQtTaskBarDummyBackend::LXQtTaskBarDummyBackend(QObject *parent) + : ILXQtTaskbarAbstractBackend(parent) +{ + +} + + +/************************************************ + * Windows function + ************************************************/ +bool LXQtTaskBarDummyBackend::supportsAction(WId, LXQtTaskBarBackendAction) const +{ + return false; +} + +bool LXQtTaskBarDummyBackend::reloadWindows() +{ + return false; +} + +QVector LXQtTaskBarDummyBackend::getCurrentWindows() const +{ + return {}; +} + +QString LXQtTaskBarDummyBackend::getWindowTitle(WId) const +{ + return QString(); +} + +bool LXQtTaskBarDummyBackend::applicationDemandsAttention(WId) const +{ + return false; +} + +QIcon LXQtTaskBarDummyBackend::getApplicationIcon(WId, int) const +{ + return QIcon(); +} + +QString LXQtTaskBarDummyBackend::getWindowClass(WId) const +{ + return QString(); +} + +LXQtTaskBarWindowLayer LXQtTaskBarDummyBackend::getWindowLayer(WId) const +{ + return LXQtTaskBarWindowLayer::Normal; +} + +bool LXQtTaskBarDummyBackend::setWindowLayer(WId, LXQtTaskBarWindowLayer) +{ + return false; +} + +LXQtTaskBarWindowState LXQtTaskBarDummyBackend::getWindowState(WId) const +{ + return LXQtTaskBarWindowState::Normal; +} + +bool LXQtTaskBarDummyBackend::setWindowState(WId, LXQtTaskBarWindowState, bool) +{ + return false; +} + +bool LXQtTaskBarDummyBackend::isWindowActive(WId) const +{ + return false; +} + +bool LXQtTaskBarDummyBackend::raiseWindow(WId, bool) +{ + return false; +} + +bool LXQtTaskBarDummyBackend::closeWindow(WId) +{ + return false; +} + +WId LXQtTaskBarDummyBackend::getActiveWindow() const +{ + return 0; +} + + +/************************************************ + * Workspaces + ************************************************/ +int LXQtTaskBarDummyBackend::getWorkspacesCount() const +{ + return 1; // Fake 1 workspace +} + +QString LXQtTaskBarDummyBackend::getWorkspaceName(int) const +{ + return QString(); +} + +int LXQtTaskBarDummyBackend::getCurrentWorkspace() const +{ + return 0; +} + +bool LXQtTaskBarDummyBackend::setCurrentWorkspace(int) +{ + return false; +} + +int LXQtTaskBarDummyBackend::getWindowWorkspace(WId) const +{ + return 0; +} + +bool LXQtTaskBarDummyBackend::setWindowOnWorkspace(WId, int) +{ + return false; +} + +void LXQtTaskBarDummyBackend::moveApplicationToPrevNextMonitor(WId, bool, bool) +{ + //No-op +} + +bool LXQtTaskBarDummyBackend::isWindowOnScreen(QScreen *, WId) const +{ + return false; +} + +/************************************************ + * X11 Specific + ************************************************/ +void LXQtTaskBarDummyBackend::moveApplication(WId) +{ + //No-op +} + +void LXQtTaskBarDummyBackend::resizeApplication(WId) +{ + //No-op +} + +void LXQtTaskBarDummyBackend::refreshIconGeometry(WId, QRect const &) +{ + //No-op +} + +bool LXQtTaskBarDummyBackend::isAreaOverlapped(const QRect &) const +{ + return false; +} + +bool LXQtTaskBarDummyBackend::isShowingDesktop() const +{ + return false; +} + +bool LXQtTaskBarDummyBackend::showDesktop(bool) +{ + return false; +} + diff --git a/panel/backends/lxqttaskbardummybackend.h b/panel/backends/lxqttaskbardummybackend.h new file mode 100644 index 000000000..d4e1ca4bc --- /dev/null +++ b/panel/backends/lxqttaskbardummybackend.h @@ -0,0 +1,86 @@ +#ifndef LXQTTASKBARDUMMYBACKEND_H +#define LXQTTASKBARDUMMYBACKEND_H + +#include "ilxqttaskbarabstractbackend.h" + +class LXQtTaskBarDummyBackend : public ILXQtTaskbarAbstractBackend +{ + Q_OBJECT + +public: + explicit LXQtTaskBarDummyBackend(QObject *parent = nullptr); + + // Backend + bool supportsAction(WId windowId, LXQtTaskBarBackendAction action) const override; + + // Windows + bool reloadWindows() override; + + QVector getCurrentWindows() const override; + + QString getWindowTitle(WId windowId) const override; + + bool applicationDemandsAttention(WId windowId) const override; + + QIcon getApplicationIcon(WId windowId, int fallbackDevicePixels) const override; + + QString getWindowClass(WId windowId) const override; + + LXQtTaskBarWindowLayer getWindowLayer(WId windowId) const override; + bool setWindowLayer(WId windowId, LXQtTaskBarWindowLayer layer) override; + + LXQtTaskBarWindowState getWindowState(WId windowId) const override; + bool setWindowState(WId windowId, LXQtTaskBarWindowState state, bool set = true) override; + + bool isWindowActive(WId windowId) const override; + bool raiseWindow(WId windowId, bool onCurrentWorkSpace) override; + + bool closeWindow(WId windowId) override; + + WId getActiveWindow() const override; + + // Workspaces + int getWorkspacesCount() const override; + QString getWorkspaceName(int idx) const override; + + int getCurrentWorkspace() const override; + bool setCurrentWorkspace(int idx) override; + + int getWindowWorkspace(WId windowId) const override; + bool setWindowOnWorkspace(WId windowId, int idx) override; + + void moveApplicationToPrevNextMonitor(WId windowId, bool next, bool raiseOnCurrentDesktop) override; + + bool isWindowOnScreen(QScreen *screen, WId windowId) const override; + + // X11 Specific + void moveApplication(WId windowId) override; + void resizeApplication(WId windowId) override; + + void refreshIconGeometry(WId windowId, const QRect &geom) override; + + // Panel internal + bool isAreaOverlapped(const QRect& area) const override; + + // Show Destop + bool isShowingDesktop() const override; + bool showDesktop(bool value) override; + +signals: + void reloaded(); + + // Windows + void windowAdded(WId windowId); + void windowRemoved(WId windowId); + void windowPropertyChanged(WId windowId, int prop); + + // Workspaces + void workspacesCountChanged(); + void workspaceNameChanged(int idx); + void currentWorkspaceChanged(int idx); + + // TODO: needed? + void activeWindowChanged(WId windowId); +}; + +#endif // LXQTTASKBARDUMMYBACKEND_H diff --git a/panel/backends/lxqttaskbartypes.h b/panel/backends/lxqttaskbartypes.h new file mode 100644 index 000000000..9e12092bb --- /dev/null +++ b/panel/backends/lxqttaskbartypes.h @@ -0,0 +1,55 @@ +#ifndef LXQTTASKBARTYPES_H +#define LXQTTASKBARTYPES_H + +#include + +typedef quintptr WId; + +enum class LXQtTaskBarBackendAction +{ + Move = 0, + Resize, + Maximize, + MaximizeVertically, + MaximizeHorizontally, + Minimize, + RollUp, + FullScreen +}; + +enum class LXQtTaskBarWindowProperty +{ + Title = 0, + Icon, + State, + Geometry, + Urgency, + WindowClass, + Workspace +}; + +enum class LXQtTaskBarWindowState +{ + Hidden = 0, + FullScreen, + Minimized, + Maximized, + MaximizedVertically, + MaximizedHorizontally, + Normal, + RolledUp //Shaded +}; + +enum class LXQtTaskBarWindowLayer +{ + KeepBelow = 0, + Normal, + KeepAbove +}; + +enum class LXQtTaskBarWorkspace +{ + ShowOnAll = -1 +}; + +#endif // LXQTTASKBARTYPES_H diff --git a/panel/backends/xcb/CMakeLists.txt b/panel/backends/xcb/CMakeLists.txt new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/panel/backends/xcb/CMakeLists.txt @@ -0,0 +1 @@ + diff --git a/panel/backends/xcb/lxqttaskbarbackend_x11.cpp b/panel/backends/xcb/lxqttaskbarbackend_x11.cpp new file mode 100644 index 000000000..822afed51 --- /dev/null +++ b/panel/backends/xcb/lxqttaskbarbackend_x11.cpp @@ -0,0 +1,630 @@ +#include "lxqttaskbarbackend_x11.h" + +#include +#include +#include + +// Necessary for closeApplication() +#include + +#include +#include + +#include + +//NOTE: Xlib.h defines Bool which conflicts with QJsonValue::Type enum +#include +#undef Bool + +LXQtTaskbarX11Backend::LXQtTaskbarX11Backend(QObject *parent) + : ILXQtTaskbarAbstractBackend(parent) +{ + auto *x11Application = qGuiApp->nativeInterface(); + Q_ASSERT_X(x11Application, "LXQtTaskbarX11Backend", "Constructed without X11 connection"); + m_X11Display = x11Application->display(); + m_xcbConnection = x11Application->connection(); + + connect(KX11Extras::self(), &KX11Extras::windowChanged, this, &LXQtTaskbarX11Backend::onWindowChanged); + connect(KX11Extras::self(), &KX11Extras::windowAdded, this, &LXQtTaskbarX11Backend::onWindowAdded); + connect(KX11Extras::self(), &KX11Extras::windowRemoved, this, &LXQtTaskbarX11Backend::onWindowRemoved); + + connect(KX11Extras::self(), &KX11Extras::numberOfDesktopsChanged, this, &ILXQtTaskbarAbstractBackend::workspacesCountChanged); + connect(KX11Extras::self(), &KX11Extras::currentDesktopChanged, this, &ILXQtTaskbarAbstractBackend::currentWorkspaceChanged); + + connect(KX11Extras::self(), &KX11Extras::activeWindowChanged, this, &ILXQtTaskbarAbstractBackend::activeWindowChanged); +} + +/************************************************ + * Model slots + ************************************************/ +void LXQtTaskbarX11Backend::onWindowChanged(WId windowId, NET::Properties prop, NET::Properties2 prop2) +{ + if(!m_windows.contains(windowId)) + return; + + if(!acceptWindow(windowId)) + { + onWindowRemoved(windowId); + return; + } + + if (prop.testFlag(NET::WMGeometry)) + { + emit windowPropertyChanged(windowId, int(LXQtTaskBarWindowProperty::Geometry)); + } + + if (prop2.testFlag(NET::WM2WindowClass)) + { + emit windowPropertyChanged(windowId, int(LXQtTaskBarWindowProperty::WindowClass)); + } + + // window changed virtual desktop + if (prop.testFlag(NET::WMDesktop) || prop.testFlag(NET::WMGeometry)) + { + emit windowPropertyChanged(windowId, int(LXQtTaskBarWindowProperty::Workspace)); + } + + if (prop.testFlag(NET::WMVisibleName) || prop.testFlag(NET::WMName)) + emit windowPropertyChanged(windowId, int(LXQtTaskBarWindowProperty::Title)); + + // XXX: we are setting window icon geometry -> don't need to handle NET::WMIconGeometry + // Icon of the button can be based on windowClass + if (prop.testFlag(NET::WMIcon) || prop2.testFlag(NET::WM2WindowClass)) + emit windowPropertyChanged(windowId, int(LXQtTaskBarWindowProperty::Icon)); + + bool update_urgency = false; + if (prop2.testFlag(NET::WM2Urgency)) + { + update_urgency = true; + } + + if (prop.testFlag(NET::WMState)) + { + update_urgency = true; + + emit windowPropertyChanged(windowId, int(LXQtTaskBarWindowProperty::State)); + } + + if (update_urgency) + emit windowPropertyChanged(windowId, int(LXQtTaskBarWindowProperty::Urgency)); +} + +void LXQtTaskbarX11Backend::onWindowAdded(WId windowId) +{ + if(m_windows.contains(windowId)) + return; + + if (!acceptWindow(windowId)) + return; + + addWindow_internal(windowId); +} + +void LXQtTaskbarX11Backend::onWindowRemoved(WId windowId) +{ + const int row = m_windows.indexOf(windowId); + if(row == -1) + return; + + m_windows.removeAt(row); + + emit windowRemoved(windowId); +} + +/************************************************ + * Model private functions + ************************************************/ +bool LXQtTaskbarX11Backend::acceptWindow(WId windowId) const +{ + QFlags ignoreList; + ignoreList |= NET::DesktopMask; + ignoreList |= NET::DockMask; + ignoreList |= NET::SplashMask; + ignoreList |= NET::ToolbarMask; + ignoreList |= NET::MenuMask; + ignoreList |= NET::PopupMenuMask; + ignoreList |= NET::NotificationMask; + + KWindowInfo info(windowId, NET::WMWindowType | NET::WMState, NET::WM2TransientFor); + if (!info.valid()) + return false; + + if (NET::typeMatchesMask(info.windowType(NET::AllTypesMask), ignoreList)) + return false; + + if (info.state() & NET::SkipTaskbar) + return false; + + // WM_TRANSIENT_FOR hint not set - normal window + WId transFor = info.transientFor(); + + WId appRootWindow = XDefaultRootWindow(m_X11Display); + + if (transFor == 0 || transFor == windowId || transFor == appRootWindow) + return true; + + info = KWindowInfo(transFor, NET::WMWindowType); + + QFlags normalFlag; + normalFlag |= NET::NormalMask; + normalFlag |= NET::DialogMask; + normalFlag |= NET::UtilityMask; + + return !NET::typeMatchesMask(info.windowType(NET::AllTypesMask), normalFlag); +} + +void LXQtTaskbarX11Backend::addWindow_internal(WId windowId, bool emitAdded) +{ + m_windows.append(windowId); + if(emitAdded) + emit windowAdded(windowId); +} + + +/************************************************ + * Windows function + ************************************************/ +bool LXQtTaskbarX11Backend::supportsAction(WId windowId, LXQtTaskBarBackendAction action) const +{ + NET::Action x11Action; + + switch (action) + { + case LXQtTaskBarBackendAction::Move: + x11Action = NET::ActionMove; + break; + + case LXQtTaskBarBackendAction::Resize: + x11Action = NET::ActionResize; + break; + + case LXQtTaskBarBackendAction::Maximize: + x11Action = NET::ActionMax; + break; + + case LXQtTaskBarBackendAction::MaximizeVertically: + x11Action = NET::ActionMaxVert; + break; + + case LXQtTaskBarBackendAction::MaximizeHorizontally: + x11Action = NET::ActionMaxHoriz; + break; + + case LXQtTaskBarBackendAction::Minimize: + x11Action = NET::ActionMinimize; + break; + + case LXQtTaskBarBackendAction::RollUp: + x11Action = NET::ActionShade; + break; + + case LXQtTaskBarBackendAction::FullScreen: + x11Action = NET::ActionFullScreen; + break; + + default: + return false; + } + + KWindowInfo info(windowId, NET::Properties(), NET::WM2AllowedActions); + return info.actionSupported(x11Action); +} + +bool LXQtTaskbarX11Backend::reloadWindows() +{ + QVector oldWindows; + qSwap(oldWindows, m_windows); + + // Just add new windows to groups, deleting is up to the groups + const auto x11windows = KX11Extras::stackingOrder(); + for (auto const windowId: x11windows) + { + if (acceptWindow(windowId)) + { + bool emitAdded = !oldWindows.contains(windowId); + addWindow_internal(windowId, emitAdded); + } + } + + //emulate windowRemoved if known window not reported by KWindowSystem + for (auto i = oldWindows.begin(), i_e = oldWindows.end(); i != i_e; i++) + { + WId windowId = *i; + if (!m_windows.contains(windowId)) + { + //TODO: more efficient method? + emit windowRemoved(windowId); + } + } + + //TODO: refreshPlaceholderVisibility() + emit reloaded(); + + return true; +} + +QVector LXQtTaskbarX11Backend::getCurrentWindows() const +{ + return m_windows; +} + +QString LXQtTaskbarX11Backend::getWindowTitle(WId windowId) const +{ + KWindowInfo info(windowId, NET::WMVisibleName | NET::WMName); + QString title = info.visibleName().isEmpty() ? info.name() : info.visibleName(); + return title; +} + +bool LXQtTaskbarX11Backend::applicationDemandsAttention(WId windowId) const +{ + WId appRootWindow = XDefaultRootWindow(m_X11Display); + return NETWinInfo(m_xcbConnection, windowId, appRootWindow, NET::Properties{}, NET::WM2Urgency).urgency() + || KWindowInfo{windowId, NET::WMState}.hasState(NET::DemandsAttention); +} + +QIcon LXQtTaskbarX11Backend::getApplicationIcon(WId windowId, int devicePixels) const +{ + return KX11Extras::icon(windowId, devicePixels, devicePixels); +} + +QString LXQtTaskbarX11Backend::getWindowClass(WId windowId) const +{ + KWindowInfo info(windowId, NET::Properties(), NET::WM2WindowClass); + return QString::fromUtf8(info.windowClassClass()); +} + +LXQtTaskBarWindowLayer LXQtTaskbarX11Backend::getWindowLayer(WId windowId) const +{ + NET::States state = KWindowInfo(windowId, NET::WMState).state(); + if(state.testFlag(NET::KeepAbove)) + return LXQtTaskBarWindowLayer::KeepAbove; + else if(state.testFlag(NET::KeepBelow)) + return LXQtTaskBarWindowLayer::KeepBelow; + return LXQtTaskBarWindowLayer::Normal; +} + +bool LXQtTaskbarX11Backend::setWindowLayer(WId windowId, LXQtTaskBarWindowLayer layer) +{ + switch(layer) + { + case LXQtTaskBarWindowLayer::KeepAbove: + KX11Extras::clearState(windowId, NET::KeepBelow); + KX11Extras::setState(windowId, NET::KeepAbove); + break; + + case LXQtTaskBarWindowLayer::KeepBelow: + KX11Extras::clearState(windowId, NET::KeepAbove); + KX11Extras::setState(windowId, NET::KeepBelow); + break; + + default: + KX11Extras::clearState(windowId, NET::KeepBelow); + KX11Extras::clearState(windowId, NET::KeepAbove); + break; + } + + return true; +} + +LXQtTaskBarWindowState LXQtTaskbarX11Backend::getWindowState(WId windowId) const +{ + KWindowInfo info(windowId,NET::WMState | NET::XAWMState); + if(info.isMinimized()) + return LXQtTaskBarWindowState::Minimized; + + NET::States state = info.state(); + if(state.testFlag(NET::Hidden)) + return LXQtTaskBarWindowState::Hidden; + if(state.testFlag(NET::Max)) + return LXQtTaskBarWindowState::Maximized; + if(state.testFlag(NET::MaxHoriz)) + return LXQtTaskBarWindowState::MaximizedHorizontally; + if(state.testFlag(NET::MaxVert)) + return LXQtTaskBarWindowState::MaximizedVertically; + if(state.testFlag(NET::Shaded)) + return LXQtTaskBarWindowState::RolledUp; + if(state.testFlag(NET::FullScreen)) + return LXQtTaskBarWindowState::FullScreen; + + return LXQtTaskBarWindowState::Normal; +} + +bool LXQtTaskbarX11Backend::setWindowState(WId windowId, LXQtTaskBarWindowState state, bool set) +{ + // NOTE: window activation is left to the caller + + NET::State x11State; + + switch (state) + { + case LXQtTaskBarWindowState::Minimized: + { + if(set) + KX11Extras::minimizeWindow(windowId); + else + KX11Extras::unminimizeWindow(windowId); + return true; + } + case LXQtTaskBarWindowState::Maximized: + { + x11State = NET::Max; + break; + } + case LXQtTaskBarWindowState::MaximizedVertically: + { + x11State = NET::MaxVert; + break; + } + case LXQtTaskBarWindowState::MaximizedHorizontally: + { + x11State = NET::MaxHoriz; + break; + } + case LXQtTaskBarWindowState::Normal: + { + x11State = NET::Max; //TODO: correct? + break; + } + case LXQtTaskBarWindowState::RolledUp: + { + x11State = NET::Shaded; + break; + } + default: + return false; + } + + if(set) + KX11Extras::setState(windowId, x11State); + else + KX11Extras::clearState(windowId, x11State); + + return true; +} + +bool LXQtTaskbarX11Backend::isWindowActive(WId windowId) const +{ + return KX11Extras::activeWindow() == windowId; +} + +bool LXQtTaskbarX11Backend::raiseWindow(WId windowId, bool onCurrentWorkSpace) +{ + if (onCurrentWorkSpace && getWindowState(windowId) == LXQtTaskBarWindowState::Minimized) + { + setWindowOnWorkspace(windowId, getCurrentWorkspace()); + } + else + { + setCurrentWorkspace(getWindowWorkspace(windowId)); + } + + // bypass focus stealing prevention + KX11Extras::forceActiveWindow(windowId); + + // Clear urgency flag + emit windowPropertyChanged(windowId, int(LXQtTaskBarWindowProperty::Urgency)); + + return true; +} + +bool LXQtTaskbarX11Backend::closeWindow(WId windowId) +{ + // FIXME: Why there is no such thing in KWindowSystem?? + NETRootInfo(m_xcbConnection, NET::CloseWindow).closeWindowRequest(windowId); + return true; +} + +WId LXQtTaskbarX11Backend::getActiveWindow() const +{ + return KX11Extras::activeWindow(); +} + + +/************************************************ + * Workspaces + ************************************************/ +int LXQtTaskbarX11Backend::getWorkspacesCount() const +{ + return KX11Extras::numberOfDesktops(); +} + +QString LXQtTaskbarX11Backend::getWorkspaceName(int idx) const +{ + return KX11Extras::desktopName(idx); +} + +int LXQtTaskbarX11Backend::getCurrentWorkspace() const +{ + return KX11Extras::currentDesktop(); +} + +bool LXQtTaskbarX11Backend::setCurrentWorkspace(int idx) +{ + if(KX11Extras::currentDesktop() == idx) + return true; + + KX11Extras::setCurrentDesktop(idx); + return true; +} + +int LXQtTaskbarX11Backend::getWindowWorkspace(WId windowId) const +{ + KWindowInfo info(windowId, NET::WMDesktop); + return info.desktop(); +} + +bool LXQtTaskbarX11Backend::setWindowOnWorkspace(WId windowId, int idx) +{ + KX11Extras::setOnDesktop(windowId, idx); + return true; +} + +void LXQtTaskbarX11Backend::moveApplicationToPrevNextMonitor(WId windowId, bool next, bool raiseOnCurrentDesktop) +{ + KWindowInfo info(windowId, NET::WMDesktop); + if (!info.isOnCurrentDesktop()) + KX11Extras::setCurrentDesktop(info.desktop()); + + if (getWindowState(windowId) == LXQtTaskBarWindowState::Minimized) + KX11Extras::unminimizeWindow(windowId); + + KX11Extras::forceActiveWindow(windowId); + + const QRect& windowGeometry = KWindowInfo(windowId, NET::WMFrameExtents).frameGeometry(); + QList screens = QGuiApplication::screens(); + if (screens.size() > 1) + { + for (int i = 0; i < screens.size(); ++i) + { + QRect screenGeometry = screens[i]->geometry(); + if (screenGeometry.intersects(windowGeometry)) + { + int targetScreen = i + (next ? 1 : -1); + if (targetScreen < 0) + targetScreen += screens.size(); + else if (targetScreen >= screens.size()) + targetScreen -= screens.size(); + + QRect targetScreenGeometry = screens[targetScreen]->geometry(); + int X = windowGeometry.x() - screenGeometry.x() + targetScreenGeometry.x(); + int Y = windowGeometry.y() - screenGeometry.y() + targetScreenGeometry.y(); + NET::States state = KWindowInfo(windowId, NET::WMState).state(); + + // NW geometry | y/x | from panel + const int flags = 1 | (0b011 << 8) | (0b010 << 12); + KX11Extras::clearState(windowId, NET::MaxHoriz | NET::MaxVert | NET::Max | NET::FullScreen); + NETRootInfo(m_xcbConnection, NET::Properties(), NET::WM2MoveResizeWindow).moveResizeWindowRequest(windowId, flags, X, Y, 0, 0); + QTimer::singleShot(200, this, [this, windowId, state, raiseOnCurrentDesktop] + { + KX11Extras::setState(windowId, state); + raiseWindow(windowId, raiseOnCurrentDesktop); + }); + break; + } + } + } +} + +bool LXQtTaskbarX11Backend::isWindowOnScreen(QScreen *screen, WId windowId) const +{ + //TODO: old code was: + //return QApplication::desktop()->screenGeometry(parentTaskBar()).intersects(KWindowInfo(mWindow, NET::WMFrameExtents).frameGeometry()); + + if(!screen) + return true; + + QRect r = KWindowInfo(windowId, NET::WMFrameExtents).frameGeometry(); + return screen->geometry().intersects(r); +} + +/************************************************ + * X11 Specific + ************************************************/ +void LXQtTaskbarX11Backend::moveApplication(WId windowId) +{ + KWindowInfo info(windowId, NET::WMDesktop); + if (!info.isOnCurrentDesktop()) + KX11Extras::setCurrentDesktop(info.desktop()); + + if (getWindowState(windowId) == LXQtTaskBarWindowState::Minimized) + KX11Extras::unminimizeWindow(windowId); + + KX11Extras::forceActiveWindow(windowId); + + const QRect& g = KWindowInfo(windowId, NET::WMGeometry).geometry(); + int X = g.center().x(); + int Y = g.center().y(); + QCursor::setPos(X, Y); + NETRootInfo(m_xcbConnection, NET::WMMoveResize).moveResizeRequest(windowId, X, Y, NET::Move); +} + +void LXQtTaskbarX11Backend::resizeApplication(WId windowId) +{ + KWindowInfo info(windowId, NET::WMDesktop); + if (!info.isOnCurrentDesktop()) + KX11Extras::setCurrentDesktop(info.desktop()); + + if (getWindowState(windowId) == LXQtTaskBarWindowState::Minimized) + KX11Extras::unminimizeWindow(windowId); + + KX11Extras::forceActiveWindow(windowId); + + const QRect& g = KWindowInfo(windowId, NET::WMGeometry).geometry(); + int X = g.bottomRight().x(); + int Y = g.bottomRight().y(); + QCursor::setPos(X, Y); + NETRootInfo(m_xcbConnection, NET::WMMoveResize).moveResizeRequest(windowId, X, Y, NET::BottomRight); +} + +void LXQtTaskbarX11Backend::refreshIconGeometry(WId windowId, QRect const & geom) +{ + // NOTE: This function announces where the task icon is, + // such that X11 WMs can perform their related animations correctly. + + WId appRootWindow = XDefaultRootWindow(m_X11Display); + + NETWinInfo info(m_xcbConnection, + windowId, + appRootWindow, + NET::WMIconGeometry, + NET::Properties2()); + NETRect const curr = info.iconGeometry(); + + // see kwindowsystem -> NETWinInfo::setIconGeometry for the scale factor + const qreal scaleFactor = qApp->devicePixelRatio(); + int xPos = geom.x() * scaleFactor; + int yPos = geom.y() * scaleFactor; + int w = geom.width() * scaleFactor; + int h = geom.height() * scaleFactor; + if (xPos == curr.pos.x && yPos == curr.pos.y && w == curr.size.width && h == curr.size.height) + return; + NETRect nrect; + nrect.pos.x = geom.x(); + nrect.pos.y = geom.y(); + nrect.size.height = geom.height(); + nrect.size.width = geom.width(); + info.setIconGeometry(nrect); +} + +bool LXQtTaskbarX11Backend::isAreaOverlapped(const QRect &area) const +{ + //TODO: reuse our m_windows cache? + QFlags ignoreList; + ignoreList |= NET::DesktopMask; + ignoreList |= NET::DockMask; + ignoreList |= NET::SplashMask; + ignoreList |= NET::MenuMask; + ignoreList |= NET::PopupMenuMask; + ignoreList |= NET::DropdownMenuMask; + ignoreList |= NET::TopMenuMask; + ignoreList |= NET::NotificationMask; + + const auto wIds = KX11Extras::stackingOrder(); + for (auto const wId : wIds) + { + KWindowInfo info(wId, NET::WMWindowType | NET::WMState | NET::WMFrameExtents | NET::WMDesktop); + if (info.valid() + // skip windows that are on other desktops + && info.isOnCurrentDesktop() + // skip shaded, minimized or hidden windows + && !(info.state() & (NET::Shaded | NET::Hidden)) + // check against the list of ignored types + && !NET::typeMatchesMask(info.windowType(NET::AllTypesMask), ignoreList)) + { + if (info.frameGeometry().intersects(area)) + return true; + } + } + return false; +} + +bool LXQtTaskbarX11Backend::isShowingDesktop() const +{ + return KWindowSystem::showingDesktop(); +} + +bool LXQtTaskbarX11Backend::showDesktop(bool value) +{ + KWindowSystem::setShowingDesktop(value); + return true; +} diff --git a/panel/backends/xcb/lxqttaskbarbackend_x11.h b/panel/backends/xcb/lxqttaskbarbackend_x11.h new file mode 100644 index 000000000..8106cda9f --- /dev/null +++ b/panel/backends/xcb/lxqttaskbarbackend_x11.h @@ -0,0 +1,87 @@ +#ifndef LXQTTASKBARBACKEND_X11_H +#define LXQTTASKBARBACKEND_X11_H + +#include "../ilxqttaskbarabstractbackend.h" + +//TODO: make PIMPL to forward declare NET::Properties, Display, xcb_connection_t +#include + +typedef struct _XDisplay Display; +struct xcb_connection_t; + +class LXQtTaskbarX11Backend : public ILXQtTaskbarAbstractBackend +{ + Q_OBJECT + +public: + explicit LXQtTaskbarX11Backend(QObject *parent = nullptr); + + // Backend + virtual bool supportsAction(WId windowId, LXQtTaskBarBackendAction action) const override; + + // Windows + virtual bool reloadWindows() override; + + virtual QVector getCurrentWindows() const override; + virtual QString getWindowTitle(WId windowId) const override; + virtual bool applicationDemandsAttention(WId windowId) const override; + virtual QIcon getApplicationIcon(WId windowId, int devicePixels) const override; + virtual QString getWindowClass(WId windowId) const override; + + virtual LXQtTaskBarWindowLayer getWindowLayer(WId windowId) const override; + virtual bool setWindowLayer(WId windowId, LXQtTaskBarWindowLayer layer) override; + + virtual LXQtTaskBarWindowState getWindowState(WId windowId) const override; + virtual bool setWindowState(WId windowId, LXQtTaskBarWindowState state, bool set) override; + + virtual bool isWindowActive(WId windowId) const override; + virtual bool raiseWindow(WId windowId, bool onCurrentWorkSpace) override; + + virtual bool closeWindow(WId windowId) override; + + virtual WId getActiveWindow() const override; + + // Workspaces + virtual int getWorkspacesCount() const override; + virtual QString getWorkspaceName(int idx) const override; + + virtual int getCurrentWorkspace() const override; + virtual bool setCurrentWorkspace(int idx) override; + + virtual int getWindowWorkspace(WId windowId) const override; + virtual bool setWindowOnWorkspace(WId windowId, int idx) override; + + virtual void moveApplicationToPrevNextMonitor(WId windowId, bool next, bool raiseOnCurrentDesktop) override; + + virtual bool isWindowOnScreen(QScreen *screen, WId windowId) const override; + + // X11 Specific + virtual void moveApplication(WId windowId) override; + virtual void resizeApplication(WId windowId) override; + + virtual void refreshIconGeometry(WId windowId, const QRect &geom) override; + + // Panel internal + virtual bool isAreaOverlapped(const QRect& area) const override; + + // Show Destop + virtual bool isShowingDesktop() const override; + virtual bool showDesktop(bool value) override; + +private slots: + void onWindowChanged(WId windowId, NET::Properties prop, NET::Properties2 prop2); + void onWindowAdded(WId windowId); + void onWindowRemoved(WId windowId); + +private: + bool acceptWindow(WId windowId) const; + void addWindow_internal(WId windowId, bool emitAdded = true); + +private: + Display *m_X11Display; + xcb_connection_t *m_xcbConnection; + + QVector m_windows; +}; + +#endif // LXQTTASKBARBACKEND_X11_H diff --git a/panel/config/configplacement.cpp b/panel/config/configplacement.cpp index d14d545c7..6ae05fe00 100644 --- a/panel/config/configplacement.cpp +++ b/panel/config/configplacement.cpp @@ -30,7 +30,7 @@ #include "../lxqtpanellimits.h" -#include +#include #include #include #include diff --git a/panel/config/configpluginswidget.cpp b/panel/config/configpluginswidget.cpp index e65c29878..9dd23d4d6 100644 --- a/panel/config/configpluginswidget.cpp +++ b/panel/config/configpluginswidget.cpp @@ -43,13 +43,13 @@ ConfigPluginsWidget::ConfigPluginsWidget(LXQtPanel *panel, QWidget* parent) : { ui->setupUi(this); - PanelPluginsModel * plugins = mPanel->mPlugins.data(); + PanelPluginsModel * plugins = mPanel->mPlugins.get(); { - QScopedPointer m(ui->listView_plugins->selectionModel()); + std::unique_ptr m(ui->listView_plugins->selectionModel()); ui->listView_plugins->setModel(plugins); } { - QScopedPointer d(ui->listView_plugins->itemDelegate()); + std::unique_ptr d(ui->listView_plugins->itemDelegate()); ui->listView_plugins->setItemDelegate(new LXQt::HtmlDelegate(QSize(16, 16), ui->listView_plugins)); } @@ -83,11 +83,11 @@ void ConfigPluginsWidget::reset() void ConfigPluginsWidget::showAddPluginDialog() { - if (mAddPluginDialog.isNull()) + if (!mAddPluginDialog) { mAddPluginDialog.reset(new AddPluginDialog); - connect(mAddPluginDialog.data(), &AddPluginDialog::pluginSelected, - mPanel->mPlugins.data(), &PanelPluginsModel::addPlugin); + connect(mAddPluginDialog.get(), &AddPluginDialog::pluginSelected, + mPanel->mPlugins.get(), &PanelPluginsModel::addPlugin); } mAddPluginDialog->show(); mAddPluginDialog->raise(); @@ -96,7 +96,7 @@ void ConfigPluginsWidget::showAddPluginDialog() void ConfigPluginsWidget::resetButtons() { - PanelPluginsModel *model = mPanel->mPlugins.data(); + PanelPluginsModel *model = mPanel->mPlugins.get(); QItemSelectionModel *selectionModel = ui->listView_plugins->selectionModel(); bool hasSelection = selectionModel->hasSelection(); bool isFirstSelected = selectionModel->isSelected(model->index(0)); diff --git a/panel/config/configpluginswidget.h b/panel/config/configpluginswidget.h index 2d3bfbda0..8afc6c45a 100644 --- a/panel/config/configpluginswidget.h +++ b/panel/config/configpluginswidget.h @@ -57,7 +57,7 @@ private slots: private: Ui::ConfigPluginsWidget *ui; - QScopedPointer mAddPluginDialog; + std::unique_ptr mAddPluginDialog; LXQtPanel *mPanel; }; diff --git a/panel/config/configstyling.cpp b/panel/config/configstyling.cpp index b30d3c80f..7035a636d 100644 --- a/panel/config/configstyling.cpp +++ b/panel/config/configstyling.cpp @@ -30,7 +30,7 @@ #include "../lxqtpanellimits.h" -#include +#include #include #include #include @@ -77,9 +77,9 @@ ConfigStyling::ConfigStyling(LXQtPanel *panel, QWidget *parent) : ************************************************/ void ConfigStyling::reset() { - mFontColor.setNamedColor(mOldFontColor.name()); + mFontColor = QColor::fromString(mOldFontColor.name()); ui->pushButton_customFontColor->setStyleSheet(QStringLiteral("background: %1").arg(mOldFontColor.name())); - mBackgroundColor.setNamedColor(mOldBackgroundColor.name()); + mBackgroundColor = QColor::fromString(mOldBackgroundColor.name()); ui->pushButton_customBgColor->setStyleSheet(QStringLiteral("background: %1").arg(mOldBackgroundColor.name())); ui->lineEdit_customBgImage->setText(mOldBackgroundImage); ui->slider_opacity->setValue(mOldOpacity); @@ -190,7 +190,7 @@ void ConfigStyling::pickFontColor() d.setWindowModality(Qt::WindowModal); if (d.exec() && d.currentColor().isValid()) { - mFontColor.setNamedColor(d.currentColor().name()); + mFontColor = QColor::fromString(d.currentColor().name()); ui->pushButton_customFontColor->setStyleSheet(QStringLiteral("background: %1").arg(mFontColor.name())); editChanged(); } @@ -206,7 +206,7 @@ void ConfigStyling::pickBackgroundColor() d.setWindowModality(Qt::WindowModal); if (d.exec() && d.currentColor().isValid()) { - mBackgroundColor.setNamedColor(d.currentColor().name()); + mBackgroundColor = QColor::fromString(d.currentColor().name()); ui->pushButton_customBgColor->setStyleSheet(QStringLiteral("background: %1").arg(mBackgroundColor.name())); editChanged(); } diff --git a/panel/lxqtpanel.cpp b/panel/lxqtpanel.cpp index 05d903089..b704fdd3d 100644 --- a/panel/lxqtpanel.cpp +++ b/panel/lxqtpanel.cpp @@ -40,7 +40,6 @@ #include #include -#include #include #include #include @@ -49,9 +48,12 @@ #include #include -#include -#include -#include +#include +#include +#include + +#include "backends/ilxqttaskbarabstractbackend.h" + // Turn on this to show the time required to load each plugin during startup // #define DEBUG_PLUGIN_LOADTIME @@ -221,8 +223,8 @@ LXQtPanel::LXQtPanel(const QString &configGroup, LXQt::Settings *settings, QWidg connect(LXQt::Settings::globalSettings(), &LXQt::GlobalSettings::settingsChanged, this, [this] { update(); } ); connect(lxqtApp, &LXQt::Application::themeChanged, this, &LXQtPanel::realign); - connect(mStandaloneWindows.data(), &WindowNotifier::firstShown, this, [this] { showPanel(true); }); - connect(mStandaloneWindows.data(), &WindowNotifier::lastHidden, this, &LXQtPanel::hidePanel); + connect(mStandaloneWindows.get(), &WindowNotifier::firstShown, this, [this] { showPanel(true); }); + connect(mStandaloneWindows.get(), &WindowNotifier::lastHidden, this, &LXQtPanel::hidePanel); readSettings(); @@ -242,18 +244,21 @@ LXQtPanel::LXQtPanel(const QString &configGroup, LXQt::Settings *settings, QWidg QTimer::singleShot(PANEL_HIDE_FIRST_TIME, this, SLOT(hidePanel())); } - connect(KX11Extras::self(), &KX11Extras::windowAdded, this, [this] { + LXQtPanelApplication *a = reinterpret_cast(qApp); + auto wmBackend = a->getWMBackend(); + + connect(wmBackend, &ILXQtTaskbarAbstractBackend::windowAdded, this, [this] { if (mHidable && mHideOnOverlap && !mHidden) { mShowDelayTimer.stop(); hidePanel(); } }); - connect(KX11Extras::self(), &KX11Extras::windowRemoved, this, [this] { + connect(wmBackend, &ILXQtTaskbarAbstractBackend::windowRemoved, this, [this] { if (mHidable && mHideOnOverlap && mHidden && !isPanelOverlapped()) mShowDelayTimer.start(); }); - connect(KX11Extras::self(), &KX11Extras::currentDesktopChanged, this, [this] { + connect(wmBackend, &ILXQtTaskbarAbstractBackend::currentWorkspaceChanged, this, [this] { if (mHidable && mHideOnOverlap) { if (!mHidden) @@ -265,12 +270,12 @@ LXQtPanel::LXQtPanel(const QString &configGroup, LXQt::Settings *settings, QWidg mShowDelayTimer.start(); } }); - connect(KX11Extras::self(), - static_cast(&KX11Extras::windowChanged), - this, [this] (WId /* id */, NET::Properties prop, NET::Properties2) { + connect(wmBackend, &ILXQtTaskbarAbstractBackend::windowPropertyChanged, + this, [this] (WId /* id */, int prop) + { if (mHidable && mHideOnOverlap // when a window is moved, resized, shaded, or minimized - && (prop.testFlag(NET::WMGeometry) || prop.testFlag(NET::WMState))) + && (prop == int(LXQtTaskBarWindowProperty::Geometry) || prop == int(LXQtTaskBarWindowProperty::State))) { if (!mHidden) { @@ -419,7 +424,8 @@ LXQtPanel::~LXQtPanel() void LXQtPanel::show() { QWidget::show(); - KX11Extras::setOnDesktop(effectiveWinId(), NET::OnAllDesktops); + if(qGuiApp->nativeInterface()) //TODO: cache in bool isPlatformX11 + KX11Extras::setOnDesktop(effectiveWinId(), NET::OnAllDesktops); } @@ -446,11 +452,11 @@ void LXQtPanel::loadPlugins() names_key += QLatin1String(CFG_KEY_PLUGINS); mPlugins.reset(new PanelPluginsModel(this, names_key, pluginDesktopDirs())); - connect(mPlugins.data(), &PanelPluginsModel::pluginAdded, mLayout, &LXQtPanelLayout::addPlugin); - connect(mPlugins.data(), &PanelPluginsModel::pluginMovedUp, mLayout, &LXQtPanelLayout::moveUpPlugin); + connect(mPlugins.get(), &PanelPluginsModel::pluginAdded, mLayout, &LXQtPanelLayout::addPlugin); + connect(mPlugins.get(), &PanelPluginsModel::pluginMovedUp, mLayout, &LXQtPanelLayout::moveUpPlugin); //reemit signals - connect(mPlugins.data(), &PanelPluginsModel::pluginAdded, this, &LXQtPanel::pluginAdded); - connect(mPlugins.data(), &PanelPluginsModel::pluginRemoved, this, &LXQtPanel::pluginRemoved); + connect(mPlugins.get(), &PanelPluginsModel::pluginAdded, this, &LXQtPanel::pluginAdded); + connect(mPlugins.get(), &PanelPluginsModel::pluginRemoved, this, &LXQtPanel::pluginRemoved); const auto plugins = mPlugins->plugins(); for (auto const & plugin : plugins) @@ -1106,7 +1112,7 @@ bool LXQtPanel::event(QEvent *event) switch (event->type()) { case QEvent::ContextMenu: - showPopupMenu(); + showPopupMenu(static_cast(event)->globalPos()); break; case QEvent::LayoutRequest: @@ -1115,22 +1121,25 @@ bool LXQtPanel::event(QEvent *event) case QEvent::WinIdChange: { - // qDebug() << "WinIdChange" << hex << effectiveWinId(); - if(effectiveWinId() == 0) - break; + if(qGuiApp->nativeInterface()) + { + // qDebug() << "WinIdChange" << hex << effectiveWinId(); + if(effectiveWinId() == 0) + break; - // Sometimes Qt needs to re-create the underlying window of the widget and - // the winId() may be changed at runtime. So we need to reset all X11 properties - // when this happens. + // Sometimes Qt needs to re-create the underlying window of the widget and + // the winId() may be changed at runtime. So we need to reset all X11 properties + // when this happens. qDebug() << "WinIdChange" << Qt::hex << effectiveWinId() << "handle" << windowHandle() << windowHandle()->screen(); - // Qt::WA_X11NetWmWindowTypeDock becomes ineffective in Qt 5 - // See QTBUG-39887: https://bugreports.qt-project.org/browse/QTBUG-39887 - // Let's use KWindowSystem for that - KWindowSystem::setType(effectiveWinId(), NET::Dock); + // Qt::WA_X11NetWmWindowTypeDock becomes ineffective in Qt 5 + // See QTBUG-39887: https://bugreports.qt-project.org/browse/QTBUG-39887 + // Let's use KWindowSystem for that + KX11Extras::setType(effectiveWinId(), NET::Dock); - updateWmStrut(); // reserve screen space for the panel - KX11Extras::setOnAllDesktops(effectiveWinId(), true); + updateWmStrut(); // reserve screen space for the panel + KX11Extras::setOnAllDesktops(effectiveWinId(), true); + } break; } case QEvent::DragEnter: @@ -1171,7 +1180,7 @@ void LXQtPanel::showEvent(QShowEvent *event) /************************************************ ************************************************/ -void LXQtPanel::showPopupMenu(Plugin *plugin) +void LXQtPanel::showPopupMenu(const QPoint& cursorPos, Plugin *plugin) { PopupMenu * menu = new PopupMenu(tr("Panel"), this); menu->setAttribute(Qt::WA_DeleteOnClose); @@ -1239,7 +1248,7 @@ void LXQtPanel::showPopupMenu(Plugin *plugin) * sometimes wrongly (it seems that this bug is somehow connected to misinterpretation * of QDesktopWidget::availableGeometry) */ - menu->setGeometry(calculatePopupWindowPos(QCursor::pos(), menu->sizeHint())); + menu->setGeometry(calculatePopupWindowPos(cursorPos, menu->sizeHint())); willShowWindow(menu); menu->show(); } @@ -1258,48 +1267,60 @@ Plugin* LXQtPanel::findPlugin(const ILXQtPanelPlugin* iPlugin) const ************************************************/ QRect LXQtPanel::calculatePopupWindowPos(QPoint const & absolutePos, QSize const & windowSize) const { - int x = absolutePos.x(), y = absolutePos.y(); + QPoint localPos = mapFromGlobal(absolutePos); + int x = localPos.x(), y = localPos.y(); switch (position()) { case ILXQtPanel::PositionTop: - y = mGeometry.bottom(); + y = geometry().height(); break; case ILXQtPanel::PositionBottom: - y = mGeometry.top() - windowSize.height(); + y = 0 - windowSize.height(); break; case ILXQtPanel::PositionLeft: - x = mGeometry.right(); + x = geometry().right(); break; case ILXQtPanel::PositionRight: - x = mGeometry.left() - windowSize.width(); + x = geometry().left() - windowSize.width(); break; } QRect res(QPoint(x, y), windowSize); - QRect panelScreen; - const auto screens = QApplication::screens(); - if (mActualScreenNum < screens.size()) - panelScreen = screens.at(mActualScreenNum)->geometry(); - // NOTE: We cannot use AvailableGeometry() which returns the work area here because when in a - // multihead setup with different resolutions. In this case, the size of the work area is limited - // by the smallest monitor and may be much smaller than the current screen and we will place the - // menu at the wrong place. This is very bad for UX. So let's use the full size of the screen. - if (res.right() > panelScreen.right()) - res.moveRight(panelScreen.right()); + // Map to global coordinates + res = QRect(mapToGlobal(res.topLeft()), mapToGlobal(res.bottomRight())); + + if(qGuiApp->nativeInterface()) + { + //On X11 we clamp rects inside screen area. + //NOTE: On Wayland it's done by compositor - if (res.bottom() > panelScreen.bottom()) - res.moveBottom(panelScreen.bottom()); + QRect panelScreen; + const auto screens = QApplication::screens(); + if (mActualScreenNum < screens.size()) + panelScreen = screens.at(mActualScreenNum)->geometry(); - if (res.left() < panelScreen.left()) - res.moveLeft(panelScreen.left()); + // NOTE: We cannot use AvailableGeometry() which returns the work area here because when in a + // multihead setup with different resolutions. In this case, the size of the work area is limited + // by the smallest monitor and may be much smaller than the current screen and we will place the + // menu at the wrong place. This is very bad for UX. So let's use the full size of the screen. - if (res.top() < panelScreen.top()) - res.moveTop(panelScreen.top()); + if (res.right() > panelScreen.right()) + res.moveRight(panelScreen.right()); + + if (res.bottom() > panelScreen.bottom()) + res.moveBottom(panelScreen.bottom() - mGeometry.top()); + + if (res.left() < panelScreen.left()) + res.moveLeft(panelScreen.left()); + + if (res.top() < panelScreen.top()) + res.moveTop(panelScreen.top() - mGeometry.top()); + } return res; } @@ -1321,7 +1342,7 @@ QRect LXQtPanel::calculatePopupWindowPos(const ILXQtPanelPlugin *plugin, const Q } // Note: assuming there are not contentMargins around the "BackgroundWidget" (LXQtPanelWidget) - return calculatePopupWindowPos(mGeometry.topLeft() + panel_plugin->geometry().topLeft(), windowSize); + return calculatePopupWindowPos(mapToGlobal(panel_plugin->geometry().topLeft()), windowSize); } @@ -1404,33 +1425,11 @@ void LXQtPanel::userRequestForDeletion() bool LXQtPanel::isPanelOverlapped() const { - QFlags ignoreList; - ignoreList |= NET::DesktopMask; - ignoreList |= NET::DockMask; - ignoreList |= NET::SplashMask; - ignoreList |= NET::MenuMask; - ignoreList |= NET::PopupMenuMask; - ignoreList |= NET::DropdownMenuMask; - ignoreList |= NET::TopMenuMask; - ignoreList |= NET::NotificationMask; - - const auto wIds = KX11Extras::stackingOrder(); - for (auto const wId : wIds) - { - KWindowInfo info(wId, NET::WMWindowType | NET::WMState | NET::WMFrameExtents | NET::WMDesktop); - if (info.valid() - // skip windows that are on other desktops - && info.isOnCurrentDesktop() - // skip shaded, minimized or hidden windows - && !(info.state() & (NET::Shaded | NET::Hidden)) - // check against the list of ignored types - && !NET::typeMatchesMask(info.windowType(NET::AllTypesMask), ignoreList)) - { - if (info.frameGeometry().intersects(mGeometry)) - return true; - } - } - return false; + LXQtPanelApplication *a = reinterpret_cast(qApp); + + //TODO: calculate geometry on wayland + QRect area = mGeometry; + return a->getWMBackend()->isAreaOverlapped(area); } void LXQtPanel::showPanel(bool animate) diff --git a/panel/lxqtpanel.h b/panel/lxqtpanel.h index f3be5cd96..a3a061a53 100644 --- a/panel/lxqtpanel.h +++ b/panel/lxqtpanel.h @@ -135,10 +135,11 @@ class LXQT_PANEL_API LXQtPanel : public QFrame, public ILXQtPanel * is given as parameter, the menu will be divided in two groups: * plugin-specific options and panel-related options. As these two are * shown together, this menu has to be created by LXQtPanel. + * @param cursorPos The global cursor pos * @param plugin The plugin whose menu options will be included in the * context menu. */ - void showPopupMenu(Plugin *plugin = 0); + void showPopupMenu(const QPoint &cursorPos, Plugin *plugin = nullptr); // ILXQtPanel overrides ........ ILXQtPanel::Position position() const override { return mPosition; } @@ -470,12 +471,12 @@ private slots: * @brief Pointer to the PanelPluginsModel which will store all the Plugins * that are loaded. */ - QScopedPointer mPlugins; + std::unique_ptr mPlugins; /** * @brief object for storing info if some standalone window is shown * (for preventing hide) */ - QScopedPointer mStandaloneWindows; + std::unique_ptr mStandaloneWindows; /** * @brief Returns the screen index of a screen on which this panel could diff --git a/panel/lxqtpanelapplication.cpp b/panel/lxqtpanelapplication.cpp index c6e264839..c3b666620 100644 --- a/panel/lxqtpanelapplication.cpp +++ b/panel/lxqtpanelapplication.cpp @@ -25,29 +25,48 @@ * * END_COMMON_COPYRIGHT_HEADER */ - #include "lxqtpanelapplication.h" #include "lxqtpanelapplication_p.h" -#include "lxqtpanel.h" + #include "config/configpaneldialog.h" -#include -#include -#include +#include "lxqtpanel.h" + +#include #include +#include #include -#include +#include +#include + +#include "backends/lxqttaskbardummybackend.h" +#include "backends/xcb/lxqttaskbarbackend_x11.h" + +ILXQtTaskbarAbstractBackend *createWMBackend() +{ + if(qGuiApp->nativeInterface()) + return new LXQtTaskbarX11Backend; + + qWarning() << "\n" + << "ERROR: Could not create a backend for window managment operations.\n" + << "Only X11 supported!\n" + << "Falling back to dummy backend. Some functions will not be available.\n" + << "\n"; + + return new LXQtTaskBarDummyBackend; +} LXQtPanelApplicationPrivate::LXQtPanelApplicationPrivate(LXQtPanelApplication *q) : mSettings(nullptr), q_ptr(q) { + mWMBackend = createWMBackend(); } ILXQtPanel::Position LXQtPanelApplicationPrivate::computeNewPanelPosition(const LXQtPanel *p, const int screenNum) { Q_Q(LXQtPanelApplication); - QVector screenPositions(4, false); // false means not occupied + QList screenPositions(4, false); // false means not occupied for (int i = 0; i < q->mPanels.size(); ++i) { if (p != q->mPanels.at(i)) { @@ -131,7 +150,7 @@ LXQtPanelApplication::LXQtPanelApplication(int& argc, char** argv) panels << QStringLiteral("panel1"); } - for(const QString& i : qAsConst(panels)) + for(const QString& i : std::as_const(panels)) { addPanel(i); } @@ -199,7 +218,7 @@ void LXQtPanelApplication::reloadPanelsAsNeeded() for(const QString& name : names) { bool found = false; - for(LXQtPanel* panel : qAsConst(mPanels)) + for(LXQtPanel* panel : std::as_const(mPanels)) { if(panel->name() == name) { @@ -246,7 +265,7 @@ void LXQtPanelApplication::screenDestroyed(QObject* screenObj) QScreen* screen = static_cast(screenObj); bool reloadNeeded = false; qApp->setQuitOnLastWindowClosed(false); - for(LXQtPanel* panel : qAsConst(mPanels)) + for(LXQtPanel* panel : std::as_const(mPanels)) { QWindow* panelWindow = panel->windowHandle(); if(panelWindow && panelWindow->screen() == screen) @@ -290,6 +309,12 @@ bool LXQtPanelApplication::isPluginSingletonAndRunning(QString const & pluginId) return false; } +ILXQtTaskbarAbstractBackend *LXQtPanelApplication::getWMBackend() const +{ + Q_D(const LXQtPanelApplication); + return d->mWMBackend; +} + // See LXQtPanelApplication::LXQtPanelApplication for why this isn't good. void LXQtPanelApplication::setIconTheme(const QString &iconTheme) { @@ -300,7 +325,7 @@ void LXQtPanelApplication::setIconTheme(const QString &iconTheme) if (newTheme != QIcon::themeName()) { QIcon::setThemeName(newTheme); - for(LXQtPanel* panel : qAsConst(mPanels)) + for(LXQtPanel* panel : std::as_const(mPanels)) { panel->update(); panel->updateConfigDialog(); diff --git a/panel/lxqtpanelapplication.h b/panel/lxqtpanelapplication.h index a672e7e46..15c912884 100644 --- a/panel/lxqtpanelapplication.h +++ b/panel/lxqtpanelapplication.h @@ -37,6 +37,8 @@ class QScreen; class LXQtPanel; class LXQtPanelApplicationPrivate; +class ILXQtTaskbarAbstractBackend; + /*! * \brief The LXQtPanelApplication class inherits from LXQt::Application and * is therefore the QApplication that we will create and execute in our @@ -89,6 +91,8 @@ class LXQtPanelApplication : public LXQt::Application */ bool isPluginSingletonAndRunning(QString const & pluginId) const; + ILXQtTaskbarAbstractBackend* getWMBackend() const; + public slots: /*! * \brief Adds a new LXQtPanel which consists of the following steps: diff --git a/panel/lxqtpanelapplication_p.h b/panel/lxqtpanelapplication_p.h index 4dd26182c..db924bf62 100644 --- a/panel/lxqtpanelapplication_p.h +++ b/panel/lxqtpanelapplication_p.h @@ -27,6 +27,8 @@ namespace LXQt { class Settings; } +class ILXQtTaskbarAbstractBackend; + class LXQtPanelApplicationPrivate { Q_DECLARE_PUBLIC(LXQtPanelApplication) public: @@ -35,6 +37,7 @@ class LXQtPanelApplicationPrivate { ~LXQtPanelApplicationPrivate() {}; LXQt::Settings *mSettings; + ILXQtTaskbarAbstractBackend *mWMBackend; ILXQtPanel::Position computeNewPanelPosition(const LXQtPanel *p, const int screenNum); diff --git a/panel/lxqtpanellayout.cpp b/panel/lxqtpanellayout.cpp index 29af42ade..41b8b545b 100644 --- a/panel/lxqtpanellayout.cpp +++ b/panel/lxqtpanellayout.cpp @@ -156,7 +156,7 @@ class LayoutItemGrid void moveItem(int from, int to); private: - QVector mInfoItems; + QList mInfoItems; int mColCount; int mUsedColCount; int mRowCount; @@ -218,7 +218,7 @@ void LayoutItemGrid::rebuild() { clear(); - for(QLayoutItem *item : qAsConst(mItems)) + for(QLayoutItem *item : std::as_const(mItems)) { doAddToGrid(item); } @@ -648,7 +648,7 @@ void LXQtPanelLayout::setGeometryHoriz(const QRect &geometry) } // Calc baselines for plugins like button. - QVector baseLines(qMax(mLeftGrid->colCount(), mRightGrid->colCount())); + QList baseLines(qMax(mLeftGrid->colCount(), mRightGrid->colCount())); const int bh = geometry.height() / baseLines.count(); const int base_center = bh >> 1; const int height_remain = 0 < bh ? geometry.height() % baseLines.size() : 0; @@ -787,7 +787,7 @@ void LXQtPanelLayout::setGeometryVert(const QRect &geometry) } // Calc baselines for plugins like button. - QVector baseLines(qMax(mLeftGrid->colCount(), mRightGrid->colCount())); + QList baseLines(qMax(mLeftGrid->colCount(), mRightGrid->colCount())); const int bw = geometry.width() / baseLines.count(); const int base_center = bw >> 1; const int width_remain = 0 < bw ? geometry.width() % baseLines.size() : 0; diff --git a/panel/main.cpp b/panel/main.cpp index 1991edc93..81fe17675 100644 --- a/panel/main.cpp +++ b/panel/main.cpp @@ -37,7 +37,6 @@ int main(int argc, char *argv[]) { LXQtPanelApplication app(argc, argv); - app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); return app.exec(); } diff --git a/panel/panelpluginsmodel.cpp b/panel/panelpluginsmodel.cpp index b9f4275b4..52f63665c 100644 --- a/panel/panelpluginsmodel.cpp +++ b/panel/panelpluginsmodel.cpp @@ -224,7 +224,7 @@ void PanelPluginsModel::loadPlugins(QStringList const & desktopDirs) timer.start(); qint64 lastTime = 0; #endif - for (auto const & name : qAsConst(plugin_names)) + for (auto const & name : std::as_const(plugin_names)) { pluginslist_t::iterator i = mPlugins.insert(mPlugins.end(), {name, nullptr}); QString type = mPanel->settings()->value(name + QStringLiteral("/type")).toString(); diff --git a/panel/panelpluginsmodel.h b/panel/panelpluginsmodel.h index d76e9346f..a31bf2ad1 100644 --- a/panel/panelpluginsmodel.h +++ b/panel/panelpluginsmodel.h @@ -263,7 +263,7 @@ public slots: * * \sa mPlugins */ - typedef QList > > pluginslist_t; + typedef QList > > pluginslist_t; private: /*! @@ -320,7 +320,7 @@ public slots: * \brief mPlugins Stores all the Plugins. * * mPlugins is a QList of elements while each element corresponds to a - * single Plugin. Each element is a QPair of a QString and a QPointer + * single Plugin. Each element is a std::pair of a QString and a QPointer * while the QPointer points to a Plugin. * * To access the elements, you can use indexing or an iterator on the @@ -336,6 +336,6 @@ public slots: LXQtPanel * mPanel; }; -Q_DECLARE_METATYPE(Plugin const *) +Q_DECLARE_OPAQUE_POINTER(Plugin const *) #endif // PANELPLUGINSMODEL_H diff --git a/panel/plugin.cpp b/panel/plugin.cpp index d5c8c992e..4844bd528 100644 --- a/panel/plugin.cpp +++ b/panel/plugin.cpp @@ -31,7 +31,7 @@ #include "pluginsettings_p.h" #include "lxqtpanel.h" -#include +#include #include #include @@ -127,7 +127,7 @@ Plugin::Plugin(const LXQt::PluginInfo &desktopFile, LXQt::Settings *settings, co else { // this plugin is a dynamically loadable module QString baseName = QStringLiteral("lib%1.so").arg(desktopFile.id()); - for(const QString &dirName : qAsConst(dirs)) + for(const QString &dirName : std::as_const(dirs)) { QFileInfo fi(QDir(dirName), baseName); if (fi.exists()) @@ -380,9 +380,9 @@ void Plugin::saveSettings() /************************************************ ************************************************/ -void Plugin::contextMenuEvent(QContextMenuEvent * /*event*/) +void Plugin::contextMenuEvent(QContextMenuEvent * event) { - mPanel->showPopupMenu(this); + mPanel->showPopupMenu(event->globalPos(), this); } diff --git a/panel/pluginmoveprocessor.cpp b/panel/pluginmoveprocessor.cpp index 03928dfe9..dfb0d3632 100644 --- a/panel/pluginmoveprocessor.cpp +++ b/panel/pluginmoveprocessor.cpp @@ -86,7 +86,7 @@ void PluginMoveProcessor::doStart() ************************************************/ void PluginMoveProcessor::mouseMoveEvent(QMouseEvent *event) { - QPoint mouse = mLayout->parentWidget()->mapFromGlobal(event->globalPos()); + QPoint mouse = mLayout->parentWidget()->mapFromGlobal(event->globalPosition()).toPoint(); MousePosInfo pos = itemByMousePos(mouse); @@ -243,9 +243,7 @@ void PluginMoveProcessor::drawMark(QLayoutItem *item, MarkType markType) "border-%2: 2px solid rgba(%4, %5, %6, %7); " "border-%3: -2px solid; " "background-color: transparent; }") - .arg(widget->objectName()) - .arg(border1) - .arg(border2) + .arg(widget->objectName(), border1, border2) .arg(Plugin::moveMarkerColor().red()) .arg(Plugin::moveMarkerColor().green()) .arg(Plugin::moveMarkerColor().blue()) diff --git a/panel/pluginsettings.h b/panel/pluginsettings.h index 13faa8573..63e2016c7 100644 --- a/panel/pluginsettings.h +++ b/panel/pluginsettings.h @@ -90,7 +90,7 @@ class LXQT_PANEL_API PluginSettings : public QObject explicit PluginSettings(LXQt::Settings *settings, const QString &group, QObject *parent = nullptr); private: - QScopedPointer d_ptr; + std::unique_ptr d_ptr; Q_DECLARE_PRIVATE(PluginSettings) }; diff --git a/plugin-backlight/sliderdialog.cpp b/plugin-backlight/sliderdialog.cpp index 1af45ebd5..41d28c5ec 100644 --- a/plugin-backlight/sliderdialog.cpp +++ b/plugin-backlight/sliderdialog.cpp @@ -38,7 +38,7 @@ SliderDialog::SliderDialog(QWidget *parent) : QDialog(parent, Qt::Dialog | Qt::W QVBoxLayout *layout = new QVBoxLayout(this); layout->setSpacing(0); - layout->setMargin(2); + layout->setContentsMargins(2, 2, 2, 2); m_upButton = new QToolButton(); m_upButton->setText(QStringLiteral("☀")); diff --git a/plugin-colorpicker/colorpicker.cpp b/plugin-colorpicker/colorpicker.cpp index 0827ceddd..004314557 100644 --- a/plugin-colorpicker/colorpicker.cpp +++ b/plugin-colorpicker/colorpicker.cpp @@ -29,7 +29,6 @@ #include "colorpicker.h" #include #include -#include #include #include #include @@ -37,6 +36,10 @@ #include #include +//NOTE: Xlib.h defines Bool which conflicts with QJsonValue::Type enum +#include +#undef Bool + const QString ColorPickerWidget::svgIcon = QStringLiteral( "" @@ -143,11 +146,21 @@ void ColorPickerWidget::mouseReleaseEvent(QMouseEvent *event) if (!mCapturing) return; - WId id = QApplication::desktop()->winId(); - QPixmap pixmap = qApp->primaryScreen()->grabWindow(id, event->globalX(), event->globalY(), 1, 1); + QColor col; + + if (auto *x11Application = qGuiApp->nativeInterface()) + { + WId id = XDefaultRootWindow(x11Application->display()); + QPoint point = event->globalPosition().toPoint(); + QPixmap pixmap = qApp->primaryScreen()->grabWindow(id, point.x(), point.y(), 1, 1); - QImage img = pixmap.toImage(); - QColor col = QColor(img.pixel(0,0)); + QImage img = pixmap.toImage(); + col = QColor(img.pixel(0,0)); + } + else + { + qWarning() << "WAYLAND does not support grabbing windows"; + } mColorButton->setColor(col); paste(col.name()); @@ -185,7 +198,7 @@ void ColorPickerWidget::captureMouse() QIcon ColorPickerWidget::colorIcon(QColor color) { - QString data = svgIcon.arg(palette().color(QPalette::Text).name()).arg(color.name()); + QString data = svgIcon.arg(palette().color(QPalette::Text).name(), color.name()); QPixmap pixmap(mColorButton->iconSize()); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); diff --git a/plugin-cpuload/lxqtcpuload.cpp b/plugin-cpuload/lxqtcpuload.cpp index 8590fbce9..4cee6208e 100644 --- a/plugin-cpuload/lxqtcpuload.cpp +++ b/plugin-cpuload/lxqtcpuload.cpp @@ -28,7 +28,6 @@ #include "lxqtcpuload.h" #include "../panel/ilxqtpanelplugin.h" #include "../panel/pluginsettings.h" -#include #include #include #include diff --git a/plugin-customcommand/CMakeLists.txt b/plugin-customcommand/CMakeLists.txt index cb82cac94..49be1b866 100644 --- a/plugin-customcommand/CMakeLists.txt +++ b/plugin-customcommand/CMakeLists.txt @@ -18,7 +18,7 @@ set(UIS ) set(LIBRARIES - Qt5Xdg + Qt6Xdg ) BUILD_LXQT_PLUGIN(${PLUGIN}) diff --git a/plugin-desktopswitch/desktopswitch.cpp b/plugin-desktopswitch/desktopswitch.cpp index 380efdf9c..67f6e56eb 100644 --- a/plugin-desktopswitch/desktopswitch.cpp +++ b/plugin-desktopswitch/desktopswitch.cpp @@ -25,6 +25,7 @@ * * END_COMMON_COPYRIGHT_HEADER */ +#include #include #include #include @@ -32,9 +33,10 @@ #include #include #include -#include -#include -#include + +#include "../panel/lxqtpanelapplication.h" +#include "../panel/backends/ilxqttaskbarabstractbackend.h" + #include #include "desktopswitch.h" @@ -47,12 +49,17 @@ DesktopSwitch::DesktopSwitch(const ILXQtPanelPluginStartupInfo &startupInfo) : QObject(), ILXQtPanelPlugin(startupInfo), m_pSignalMapper(new QSignalMapper(this)), - m_desktopCount(KX11Extras::numberOfDesktops()), + m_desktopCount(0), mRows(-1), mShowOnlyActive(false), - mDesktops(new NETRootInfo(QX11Info::connection(), NET::NumberOfDesktops | NET::CurrentDesktop | NET::DesktopNames, NET::WM2DesktopLayout)), mLabelType(static_cast(-1)) { + LXQtPanelApplication *a = reinterpret_cast(qApp); + mBackend = a->getWMBackend(); + + + m_desktopCount = mBackend->getWorkspacesCount(); + m_buttons = new QButtonGroup(this); connect (m_pSignalMapper, &QSignalMapper::mappedInt, this, &DesktopSwitch::setDesktop); @@ -63,17 +70,16 @@ DesktopSwitch::DesktopSwitch(const ILXQtPanelPluginStartupInfo &startupInfo) : settingsChanged(); - onCurrentDesktopChanged(KX11Extras::currentDesktop()); + onCurrentDesktopChanged(mBackend->getCurrentWorkspace()); QTimer::singleShot(0, this, SLOT(registerShortcuts())); connect(m_buttons, &QButtonGroup::idClicked, this, &DesktopSwitch::setDesktop); - connect(KX11Extras::self(), &KX11Extras::numberOfDesktopsChanged, this, &DesktopSwitch::onNumberOfDesktopsChanged); - connect(KX11Extras::self(), &KX11Extras::currentDesktopChanged, this, &DesktopSwitch::onCurrentDesktopChanged); - connect(KX11Extras::self(), &KX11Extras::desktopNamesChanged, this, &DesktopSwitch::onDesktopNamesChanged); + connect(mBackend, &ILXQtTaskbarAbstractBackend::workspacesCountChanged, this, &DesktopSwitch::onNumberOfDesktopsChanged); + connect(mBackend, &ILXQtTaskbarAbstractBackend::currentWorkspaceChanged, this, &DesktopSwitch::onCurrentDesktopChanged); + connect(mBackend, &ILXQtTaskbarAbstractBackend::workspaceNameChanged, this, &DesktopSwitch::onDesktopNamesChanged); - connect(KX11Extras::self(), static_cast(&KX11Extras::windowChanged), - this, &DesktopSwitch::onWindowChanged); + connect(mBackend, &ILXQtTaskbarAbstractBackend::windowPropertyChanged, this, &DesktopSwitch::onWindowChanged); } void DesktopSwitch::registerShortcuts() @@ -115,19 +121,18 @@ void DesktopSwitch::shortcutRegistered() } } -void DesktopSwitch::onWindowChanged(WId id, NET::Properties properties, NET::Properties2 /*properties2*/) +void DesktopSwitch::onWindowChanged(WId id, int prop) { - if (properties.testFlag(NET::WMState) && isWindowHighlightable(id)) + if (prop == int(LXQtTaskBarWindowProperty::State) && isWindowHighlightable(id)) { - KWindowInfo info = KWindowInfo(id, NET::WMDesktop | NET::WMState); - int desktop = info.desktop(); - if (!info.valid() || info.onAllDesktops()) + int desktop = mBackend->getWindowWorkspace(id); + if (desktop == int(LXQtTaskBarWorkspace::ShowOnAll)) return; else { DesktopSwitchButton *button = static_cast(m_buttons->button(desktop - 1)); if(button) - button->setUrgencyHint(id, info.hasState(NET::DemandsAttention)); + button->setUrgencyHint(id, mBackend->applicationDemandsAttention(id)); } } } @@ -137,7 +142,7 @@ void DesktopSwitch::refresh() const QList btns = m_buttons->buttons(); int i = 0; - const int current_desktop = KX11Extras::currentDesktop(); + const int current_desktop = mBackend->getCurrentWorkspace(); const int current_cnt = btns.count(); const int border = qMin(btns.count(), m_desktopCount); //update existing buttons @@ -145,9 +150,9 @@ void DesktopSwitch::refresh() { DesktopSwitchButton * button = qobject_cast(btns[i]); button->update(i, mLabelType, - KX11Extras::desktopName(i + 1).isEmpty() ? + mBackend->getWorkspaceName(i + 1).isEmpty() ? tr("Desktop %1").arg(i + 1) : - KX11Extras::desktopName(i + 1)); + mBackend->getWorkspaceName(i + 1)); button->setVisible(!mShowOnlyActive || i + 1 == current_desktop); } @@ -156,9 +161,9 @@ void DesktopSwitch::refresh() for ( ; i < m_desktopCount; ++i) { b = new DesktopSwitchButton(&mWidget, i, mLabelType, - KX11Extras::desktopName(i+1).isEmpty() ? + mBackend->getWorkspaceName(i+1).isEmpty() ? tr("Desktop %1").arg(i+1) : - KX11Extras::desktopName(i+1)); + mBackend->getWorkspaceName(i+1)); mWidget.layout()->addWidget(b); m_buttons->addButton(b, i); b->setVisible(!mShowOnlyActive || i + 1 == current_desktop); @@ -174,52 +179,23 @@ void DesktopSwitch::refresh() } } -bool DesktopSwitch::isWindowHighlightable(WId window) +bool DesktopSwitch::isWindowHighlightable(WId) { - // this method was borrowed from the taskbar plugin - QFlags ignoreList; - ignoreList |= NET::DesktopMask; - ignoreList |= NET::DockMask; - ignoreList |= NET::SplashMask; - ignoreList |= NET::ToolbarMask; - ignoreList |= NET::MenuMask; - ignoreList |= NET::PopupMenuMask; - ignoreList |= NET::NotificationMask; - - KWindowInfo info(window, NET::WMWindowType | NET::WMState, NET::WM2TransientFor); - if (!info.valid()) - return false; - - if (NET::typeMatchesMask(info.windowType(NET::AllTypesMask), ignoreList)) - return false; - - if (info.state() & NET::SkipTaskbar) - return false; - - // WM_TRANSIENT_FOR hint not set - normal window - WId transFor = info.transientFor(); - if (transFor == 0 || transFor == window || transFor == (WId) QX11Info::appRootWindow()) - return true; - - info = KWindowInfo(transFor, NET::WMWindowType); - - QFlags normalFlag; - normalFlag |= NET::NormalMask; - normalFlag |= NET::DialogMask; - normalFlag |= NET::UtilityMask; - - return !NET::typeMatchesMask(info.windowType(NET::AllTypesMask), normalFlag); + // Backend should emit signals only for higlightable windows and ignore others + // TODO: check + return true; } DesktopSwitch::~DesktopSwitch() = default; void DesktopSwitch::setDesktop(int desktop) { - KX11Extras::setCurrentDesktop(desktop + 1); + mBackend->setCurrentWorkspace(desktop + 1); } -void DesktopSwitch::onNumberOfDesktopsChanged(int count) +void DesktopSwitch::onNumberOfDesktopsChanged() { + int count = mBackend->getWorkspacesCount(); qDebug() << "Desktop count changed from" << m_desktopCount << "to" << count; m_desktopCount = count; refresh(); @@ -278,11 +254,11 @@ void DesktopSwitch::settingsChanged() int columns = static_cast(ceil(static_cast(m_desktopCount) / mRows)); if (panel()->isHorizontal()) { - mDesktops->setDesktopLayout(NET::OrientationHorizontal, columns, mRows, mWidget.isRightToLeft() ? NET::DesktopLayoutCornerTopRight : NET::DesktopLayoutCornerTopLeft); + //mDesktops->setDesktopLayout(NET::OrientationHorizontal, columns, mRows, mWidget.isRightToLeft() ? NET::DesktopLayoutCornerTopRight : NET::DesktopLayoutCornerTopLeft); } else { - mDesktops->setDesktopLayout(NET::OrientationHorizontal, mRows, columns, mWidget.isRightToLeft() ? NET::DesktopLayoutCornerTopRight : NET::DesktopLayoutCornerTopLeft); + //mDesktops->setDesktopLayout(NET::OrientationHorizontal, mRows, columns, mWidget.isRightToLeft() ? NET::DesktopLayoutCornerTopRight : NET::DesktopLayoutCornerTopLeft); } realign(); // in case it isn't called when the desktop layout changes } @@ -330,9 +306,12 @@ void DesktopSwitchWidget::wheelEvent(QWheelEvent *e) if(abs(m_mouseWheelThresholdCounter) < 100) return; - int max = KX11Extras::numberOfDesktops(); + LXQtPanelApplication *a = reinterpret_cast(qApp); + auto wmBackend = a->getWMBackend(); + + int max = wmBackend->getWorkspacesCount(); int delta = rotationSteps < 0 ? 1 : -1; - int current = KX11Extras::currentDesktop() + delta; + int current = wmBackend->getCurrentWorkspace() + delta; if (current > max){ current = 1; @@ -341,5 +320,32 @@ void DesktopSwitchWidget::wheelEvent(QWheelEvent *e) current = max; m_mouseWheelThresholdCounter = 0; - KX11Extras::setCurrentDesktop(current); + wmBackend->setCurrentWorkspace(current); +} + +ILXQtPanelPlugin *DesktopSwitchPluginLibrary::instance(const ILXQtPanelPluginStartupInfo &startupInfo) const +{ + return new DesktopSwitch{startupInfo}; + + //TODO: detect dummy backend and show unsupported message? + // Or instead remove it and make just a message box at application start + //return new DesktopSwitchUnsupported{startupInfo}; +} + +DesktopSwitchUnsupported::DesktopSwitchUnsupported(const ILXQtPanelPluginStartupInfo &startupInfo) + : ILXQtPanelPlugin(startupInfo) + , mLabel(new QLabel(tr("n/a"))) +{ + mLabel->setToolTip(tr("DesktopSwitch is unsupported on current platform: %1").arg(QGuiApplication::platformName())); +} + +DesktopSwitchUnsupported::~DesktopSwitchUnsupported() +{ + delete mLabel; + mLabel = nullptr; +} + +QWidget *DesktopSwitchUnsupported::widget() +{ + return mLabel; } diff --git a/plugin-desktopswitch/desktopswitch.h b/plugin-desktopswitch/desktopswitch.h index 73d7a9e78..b57b44c32 100644 --- a/plugin-desktopswitch/desktopswitch.h +++ b/plugin-desktopswitch/desktopswitch.h @@ -30,21 +30,19 @@ #define DESKTOPSWITCH_H #include "../panel/ilxqtpanelplugin.h" -#include #include -#include -#include -#include #include "desktopswitchbutton.h" +class QLabel; class QSignalMapper; class QButtonGroup; -class NETRootInfo; namespace LXQt { class GridLayout; } +class ILXQtTaskbarAbstractBackend; + class DesktopSwitchWidget: public QFrame { Q_OBJECT @@ -85,7 +83,7 @@ class DesktopSwitch : public QObject, public ILXQtPanelPlugin LXQt::GridLayout *mLayout; int mRows; bool mShowOnlyActive; - QScopedPointer mDesktops; + ILXQtTaskbarAbstractBackend *mBackend; DesktopSwitchButton::LabelType mLabelType; void refresh(); @@ -93,31 +91,27 @@ class DesktopSwitch : public QObject, public ILXQtPanelPlugin private slots: void setDesktop(int desktop); - void onNumberOfDesktopsChanged(int); + void onNumberOfDesktopsChanged(); void onCurrentDesktopChanged(int); void onDesktopNamesChanged(); virtual void settingsChanged(); void registerShortcuts(); void shortcutRegistered(); - void onWindowChanged(WId id, NET::Properties properties, NET::Properties2 properties2); + void onWindowChanged(WId id, int prop); }; class DesktopSwitchUnsupported : public QObject, public ILXQtPanelPlugin { Q_OBJECT public: - DesktopSwitchUnsupported(const ILXQtPanelPluginStartupInfo &startupInfo) - : ILXQtPanelPlugin(startupInfo) - , mLabel{tr("n/a")} - { - mLabel.setToolTip(tr("DesktopSwitch is unsupported on current platform: %1").arg(QGuiApplication::platformName())); - } + DesktopSwitchUnsupported(const ILXQtPanelPluginStartupInfo &startupInfo); + ~DesktopSwitchUnsupported(); QString themeId() const { return QStringLiteral("DesktopSwitchUnsupported"); } - QWidget *widget() { return &mLabel; } + QWidget *widget(); bool isSeparate() const { return true; } private: - QLabel mLabel; + QLabel *mLabel; }; class DesktopSwitchPluginLibrary: public QObject, public ILXQtPanelPluginLibrary @@ -126,13 +120,7 @@ class DesktopSwitchPluginLibrary: public QObject, public ILXQtPanelPluginLibrary // Q_PLUGIN_METADATA(IID "lxqt.org/Panel/PluginInterface/3.0") Q_INTERFACES(ILXQtPanelPluginLibrary) public: - ILXQtPanelPlugin *instance(const ILXQtPanelPluginStartupInfo &startupInfo) const - { - if (QGuiApplication::platformName() == QStringLiteral("xcb")) - return new DesktopSwitch{startupInfo}; - else - return new DesktopSwitchUnsupported{startupInfo}; - } + ILXQtPanelPlugin *instance(const ILXQtPanelPluginStartupInfo &startupInfo) const; }; #endif diff --git a/plugin-desktopswitch/desktopswitchconfiguration.cpp b/plugin-desktopswitch/desktopswitchconfiguration.cpp index 402981467..a6edb41a6 100644 --- a/plugin-desktopswitch/desktopswitchconfiguration.cpp +++ b/plugin-desktopswitch/desktopswitchconfiguration.cpp @@ -26,8 +26,9 @@ #include "desktopswitchconfiguration.h" #include "ui_desktopswitchconfiguration.h" -#include -#include + +#include "../panel/lxqtpanelapplication.h" +#include "../panel/backends/ilxqttaskbarabstractbackend.h" DesktopSwitchConfiguration::DesktopSwitchConfiguration(PluginSettings *settings, QWidget *parent) : LXQtPanelPluginConfigDialog(settings, parent), @@ -64,18 +65,25 @@ void DesktopSwitchConfiguration::loadSettings() void DesktopSwitchConfiguration::loadDesktopsNames() { - int n = KX11Extras::numberOfDesktops(); + LXQtPanelApplication *a = reinterpret_cast(qApp); + auto wmBackend = a->getWMBackend(); + + int n = wmBackend->getWorkspacesCount(); for (int i = 1; i <= n; i++) { - QLineEdit *edit = new QLineEdit(KX11Extras::desktopName(i), this); + QLineEdit *edit = new QLineEdit(wmBackend->getWorkspaceName(i), this); ((QFormLayout *) ui->namesGroupBox->layout())->addRow(tr("Desktop %1:").arg(i), edit); + //TODO: on Wayland we cannot set desktop names in a standart way + // On KWin we could use DBus org.kde.KWin as done by kcm_kwin_virtualdesktops + edit->setReadOnly(true); + // C++11 rocks! - QTimer *timer = new QTimer(this); - timer->setInterval(400); - timer->setSingleShot(true); - connect(timer, &QTimer::timeout, this, [=] { KX11Extras::setDesktopName(i, edit->text()); }); - connect(edit, &QLineEdit::textEdited, this, [=] { timer->start(); }); + //QTimer *timer = new QTimer(this); + //timer->setInterval(400); + //timer->setSingleShot(true); + //connect(timer, &QTimer::timeout, this, [=] { KX11Extras::setDesktopName(i, edit->text()); }); + //connect(edit, &QLineEdit::textEdited, this, [=] { timer->start(); }); } } diff --git a/plugin-directorymenu/CMakeLists.txt b/plugin-directorymenu/CMakeLists.txt index 319b02ddc..81103a1b4 100644 --- a/plugin-directorymenu/CMakeLists.txt +++ b/plugin-directorymenu/CMakeLists.txt @@ -16,7 +16,7 @@ set(UIS set(LIBRARIES ${LIBRARIES} - Qt5Xdg + Qt6Xdg ) include ("../cmake/BuildPlugin.cmake") diff --git a/plugin-fancymenu/lxqtfancymenuappmap.cpp b/plugin-fancymenu/lxqtfancymenuappmap.cpp index e0b461980..905b56295 100644 --- a/plugin-fancymenu/lxqtfancymenuappmap.cpp +++ b/plugin-fancymenu/lxqtfancymenuappmap.cpp @@ -230,14 +230,14 @@ LXQtFancyMenuAppMap::AppItem *LXQtFancyMenuAppMap::getAppAt(int index) return *mCachedIterator; } -QVector LXQtFancyMenuAppMap::getMatchingApps(const QString &query) const +QList LXQtFancyMenuAppMap::getMatchingApps(const QString &query) const { - QVector byName; - QVector byKeyword; + QList byName; + QList byKeyword; //TODO: implement some kind of score to get better matches on top - for(const AppItem *app : qAsConst(mAppSortedByName)) + for(const AppItem *app : std::as_const(mAppSortedByName)) { if(app->title.contains(query, Qt::CaseInsensitive)) { @@ -280,7 +280,7 @@ void LXQtFancyMenuAppMap::parseMenu(const QDomElement &menu, const QString& topL Category item; item.type = LXQtFancyMenuItemType::CategoryItem; item.menuName = e.attribute(QLatin1String("name")); - item.menuTitle = e.attribute(QLatin1Literal("title"), item.menuName); + item.menuTitle = e.attribute(QLatin1String("title"), item.menuName); QString iconName = e.attribute(QLatin1String("icon")); item.icon = XdgIcon::fromTheme(iconName); mCategories.append(item); diff --git a/plugin-fancymenu/lxqtfancymenuappmap.h b/plugin-fancymenu/lxqtfancymenuappmap.h index 698e40be4..187b327e1 100644 --- a/plugin-fancymenu/lxqtfancymenuappmap.h +++ b/plugin-fancymenu/lxqtfancymenuappmap.h @@ -30,7 +30,7 @@ #define LXQTFANCYMENUAPPMAP_H #include -#include +#include #include #include @@ -74,7 +74,7 @@ class LXQtFancyMenuAppMap LXQtFancyMenuItemType type = LXQtFancyMenuItemType::AppItem; }; - QVector apps; + QList apps; LXQtFancyMenuItemType type; }; @@ -108,7 +108,7 @@ class LXQtFancyMenuAppMap AppItem *getAppAt(int index); - QVector getMatchingApps(const QString& query) const; + QList getMatchingApps(const QString& query) const; private: void parseMenu(const QDomElement& menu, const QString &topLevelCategory); @@ -121,7 +121,7 @@ class LXQtFancyMenuAppMap typedef QMap AppMap; AppMap mAppSortedByDesktopFile; AppMap mAppSortedByName; - QVector mCategories; + QList mCategories; // Cache sort by name map access AppMap::const_iterator mCachedIterator; diff --git a/plugin-fancymenu/lxqtfancymenuappmodel.cpp b/plugin-fancymenu/lxqtfancymenuappmodel.cpp index 0baa05ed9..f72b2de11 100644 --- a/plugin-fancymenu/lxqtfancymenuappmodel.cpp +++ b/plugin-fancymenu/lxqtfancymenuappmodel.cpp @@ -176,7 +176,7 @@ bool LXQtFancyMenuAppModel::dropMimeData(const QMimeData *data_, Qt::DropAction return false; // No-op // realRow is needed because beginMoveRows() behaves differenlty than - // QVector<...>::move() on index counting. + // QList<...>::move() on index counting. beginMoveRows(QModelIndex(), oldRow, oldRow, QModelIndex(), realRow); mAppMap->moveFavoriteItem(oldRow, row); @@ -208,7 +208,7 @@ void LXQtFancyMenuAppModel::setCurrentCategory(int category) endResetModel(); } -void LXQtFancyMenuAppModel::showSearchResults(const QVector &matches) +void LXQtFancyMenuAppModel::showSearchResults(const QList &matches) { beginResetModel(); mSearchMatches = matches; diff --git a/plugin-fancymenu/lxqtfancymenuappmodel.h b/plugin-fancymenu/lxqtfancymenuappmodel.h index def2328d9..6b50cfbd4 100644 --- a/plugin-fancymenu/lxqtfancymenuappmodel.h +++ b/plugin-fancymenu/lxqtfancymenuappmodel.h @@ -59,7 +59,7 @@ class LXQtFancyMenuAppModel : public QAbstractListModel void reloadAppMap(bool end); void setCurrentCategory(int category); - void showSearchResults(const QVector &matches); + void showSearchResults(const QList &matches); void endSearch(); LXQtFancyMenuAppMap *appMap() const; @@ -77,7 +77,7 @@ class LXQtFancyMenuAppModel : public QAbstractListModel LXQtFancyMenuAppMap *mAppMap; int mCurrentCategory; - QVector mSearchMatches; + QList mSearchMatches; bool mInSearch; }; diff --git a/plugin-kbindicator/CMakeLists.txt b/plugin-kbindicator/CMakeLists.txt index 29a208f9d..0a5e36192 100644 --- a/plugin-kbindicator/CMakeLists.txt +++ b/plugin-kbindicator/CMakeLists.txt @@ -29,9 +29,9 @@ set(UIS set(LIBRARIES ) -find_package(XCB REQUIRED COMPONENTS xcb xcb-xkb) +find_package(XCB REQUIRED COMPONENTS XCB XKB) find_package(XKBCommon REQUIRED COMPONENTS XKBCommon X11) -find_package(Qt5 ${QT_MINIMUM_VERSION} REQUIRED COMPONENTS X11Extras Xml) +find_package(Qt6 ${QT_MINIMUM_VERSION} REQUIRED COMPONENTS Xml) include_directories(${XCB_INCLUDE_DIRS}) @@ -50,7 +50,7 @@ set(LIBRARIES ${XCB_LIBRARIES} XKBCommon::XKBCommon XKBCommon::X11 - Qt5::Xml + Qt6::Xml ) add_definitions(-DX11_ENABLED) diff --git a/plugin-kbindicator/kbindicator-plugin.cpp b/plugin-kbindicator/kbindicator-plugin.cpp index b2e69b0c8..ab0580e33 100644 --- a/plugin-kbindicator/kbindicator-plugin.cpp +++ b/plugin-kbindicator/kbindicator-plugin.cpp @@ -26,10 +26,13 @@ #include #include -#include + +#include // For nativeInterface() + #include "src/kbdstate.h" #include "../panel/ilxqtpanelplugin.h" + class LXQtKbIndicatorPlugin: public QObject, public ILXQtPanelPluginLibrary { Q_OBJECT @@ -40,11 +43,14 @@ class LXQtKbIndicatorPlugin: public QObject, public ILXQtPanelPluginLibrary ILXQtPanelPlugin *instance(const ILXQtPanelPluginStartupInfo &startupInfo) const override { - // Currently only X11 supported - if (!QX11Info::connection()) { + auto *x11Application = qGuiApp->nativeInterface(); + if(!x11Application || !x11Application->connection()) + { + // Currently only X11 supported qWarning() << "Currently kbindicator plugin supports X11 only. Skipping."; return nullptr; } + return new KbdState(startupInfo); } }; diff --git a/plugin-kbindicator/src/kbdkeeper.cpp b/plugin-kbindicator/src/kbdkeeper.cpp index 2f53db04b..49009934b 100644 --- a/plugin-kbindicator/src/kbdkeeper.cpp +++ b/plugin-kbindicator/src/kbdkeeper.cpp @@ -25,9 +25,11 @@ * END_COMMON_COPYRIGHT_HEADER */ #include -#include -#include -#include + +#include +#include +#include + #include "kbdkeeper.h" //-------------------------------------------------------------------------------------------------- diff --git a/plugin-kbindicator/src/kbdwatcher.cpp b/plugin-kbindicator/src/kbdwatcher.cpp index 0cf4da74a..0ba9309ce 100644 --- a/plugin-kbindicator/src/kbdwatcher.cpp +++ b/plugin-kbindicator/src/kbdwatcher.cpp @@ -61,7 +61,7 @@ void KbdWatcher::createKeeper(KeeperType type) break; } - connect(m_keeper.data(), &KbdKeeper::changed, this, &KbdWatcher::keeperChanged); + connect(m_keeper.get(), &KbdKeeper::changed, this, &KbdWatcher::keeperChanged); m_keeper->setup(); keeperChanged(); diff --git a/plugin-kbindicator/src/kbdwatcher.h b/plugin-kbindicator/src/kbdwatcher.h index 15553d44a..187d0cde3 100644 --- a/plugin-kbindicator/src/kbdwatcher.h +++ b/plugin-kbindicator/src/kbdwatcher.h @@ -58,7 +58,7 @@ private slots: private: KbdLayout m_layout; - QScopedPointer m_keeper; + std::unique_ptr m_keeper; }; #endif diff --git a/plugin-kbindicator/src/x11/kbdlayout.cpp b/plugin-kbindicator/src/x11/kbdlayout.cpp index 90c2b0bcc..f5dbe2915 100644 --- a/plugin-kbindicator/src/x11/kbdlayout.cpp +++ b/plugin-kbindicator/src/x11/kbdlayout.cpp @@ -97,7 +97,7 @@ class X11Kbd: public QAbstractNativeEventFilter bool isEnabled() const { return true; } - bool nativeEventFilter(const QByteArray &eventType, void *message, long *) override + bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *) override { if (eventType != "xcb_generic_event_t") return false; diff --git a/plugin-kbindicator/src/x11/kbdlayout.h b/plugin-kbindicator/src/x11/kbdlayout.h index fdb4df2f1..c97c68869 100644 --- a/plugin-kbindicator/src/x11/kbdlayout.h +++ b/plugin-kbindicator/src/x11/kbdlayout.h @@ -54,7 +54,7 @@ class X11Kbd: public QObject void checkState(); void keyboardChanged(); private: - QScopedPointer m_priv; + std::unique_ptr m_priv; }; #endif diff --git a/plugin-mainmenu/actionview.cpp b/plugin-mainmenu/actionview.cpp index f585fcebe..ce0f3e306 100644 --- a/plugin-mainmenu/actionview.cpp +++ b/plugin-mainmenu/actionview.cpp @@ -164,11 +164,11 @@ ActionView::ActionView(QWidget * parent /*= nullptr*/) mProxy->setFilterCaseSensitivity(Qt::CaseInsensitive); mProxy->sort(0); { - QScopedPointer guard{selectionModel()}; + std::unique_ptr guard{selectionModel()}; setModel(mProxy); } { - QScopedPointer guard{itemDelegate()}; + std::unique_ptr guard{itemDelegate()}; setItemDelegate(new DelayedIconDelegate{this}); } connect(this, &QAbstractItemView::activated, this, &ActionView::onActivated); @@ -284,7 +284,7 @@ QSize ActionView::minimumSizeHint() const void ActionView::mousePressEvent(QMouseEvent* event) { if (event->button() == Qt::LeftButton) - mDragStartPosition = event->pos(); + mDragStartPosition = event->position().toPoint(); QListView::mousePressEvent(event); } @@ -294,7 +294,7 @@ void ActionView::mouseMoveEvent(QMouseEvent *event) if (!(event->buttons() & Qt::LeftButton)) return; - if ((event->pos() - mDragStartPosition).manhattanLength() < QApplication::startDragDistance()) + if ((event->position().toPoint() - mDragStartPosition).manhattanLength() < QApplication::startDragDistance()) return; XdgAction *a = qobject_cast(indexAt(mDragStartPosition).data(ActionView::ActionRole).value()); diff --git a/plugin-mainmenu/lxqtmainmenu.cpp b/plugin-mainmenu/lxqtmainmenu.cpp index a689db423..0f55cdfbd 100644 --- a/plugin-mainmenu/lxqtmainmenu.cpp +++ b/plugin-mainmenu/lxqtmainmenu.cpp @@ -54,6 +54,7 @@ #include #include #include + #include #endif #define DEFAULT_SHORTCUT "Alt+F1" diff --git a/plugin-mount/CMakeLists.txt b/plugin-mount/CMakeLists.txt index a9a0a1e42..5f817ff51 100644 --- a/plugin-mount/CMakeLists.txt +++ b/plugin-mount/CMakeLists.txt @@ -34,7 +34,7 @@ set(UIS configuration.ui ) -find_package(KF5Solid ${QT_MINIMUM_VERSION} REQUIRED) -set(LIBRARIES Qt5Xdg lxqt-globalkeys KF5::Solid) +find_package(KF6Solid ${QT_MINIMUM_VERSION} REQUIRED) +set(LIBRARIES Qt6Xdg lxqt-globalkeys KF6::Solid) BUILD_LXQT_PLUGIN(${PLUGIN}) diff --git a/plugin-mount/configuration.cpp b/plugin-mount/configuration.cpp index da60133c2..9c49a9dbb 100644 --- a/plugin-mount/configuration.cpp +++ b/plugin-mount/configuration.cpp @@ -39,18 +39,30 @@ Configuration::Configuration(PluginSettings *settings, QWidget *parent) : { ui->setupUi(this); - ui->devAddedLabel->sizePolicy().setHorizontalStretch(1); + // Set size policies + QSizePolicy sp = ui->devAddedLabel->sizePolicy(); + sp.setHorizontalStretch(1); + ui->devAddedLabel->setSizePolicy(sp); + sp = ui->devAddedCombo->sizePolicy(); + sp.setHorizontalStretch(1); + ui->devAddedCombo->setSizePolicy(sp); + + sp = ui->ejectPressedLabel->sizePolicy(); + sp.setHorizontalStretch(1); + ui->ejectPressedLabel->setSizePolicy(sp); + + sp = ui->ejectPressedCombo->sizePolicy(); + sp.setHorizontalStretch(1); + ui->ejectPressedCombo->setSizePolicy(sp); + + // Fill combo boxes ui->devAddedCombo->addItem(tr("Popup menu"), QLatin1String(ACT_SHOW_MENU)); ui->devAddedCombo->addItem(tr("Show info"), QLatin1String(ACT_SHOW_INFO)); ui->devAddedCombo->addItem(tr("Do nothing"), QLatin1String(ACT_NOTHING)); - ui->devAddedCombo->sizePolicy().setHorizontalStretch(1); - - ui->ejectPressedLabel->sizePolicy().setHorizontalStretch(1); ui->ejectPressedCombo->addItem(tr("Do nothing"), QLatin1String(ACT_NOTHING)); ui->ejectPressedCombo->addItem(tr("Eject All Optical Drives"), QLatin1String(ACT_EJECT_OPTICAL)); - ui->ejectPressedCombo->sizePolicy().setHorizontalStretch(1); adjustSize(); diff --git a/plugin-mount/menudiskitem.cpp b/plugin-mount/menudiskitem.cpp index bf4a52f21..3f4af34ab 100644 --- a/plugin-mount/menudiskitem.cpp +++ b/plugin-mount/menudiskitem.cpp @@ -65,7 +65,7 @@ MenuDiskItem::MenuDiskItem(Solid::Device device, Popup *popup): QHBoxLayout *layout = new QHBoxLayout(this); layout->addWidget(mDiskButton); layout->addWidget(mEjectButton); - layout->setMargin(0); + layout->setContentsMargins(QMargins()); layout->setSpacing(0); setLayout(layout); @@ -151,7 +151,7 @@ void MenuDiskItem::onMounted(Solid::ErrorType error, QVariant resultData, const else { QString errorMsg = tr("Mounting of \"%1\" failed: %2"); - errorMsg = errorMsg.arg(mDevice.description()).arg(resultData.toString()); + errorMsg = errorMsg.arg(mDevice.description(), resultData.toString()); LXQt::Notification::notify(tr("Removable media/devices manager"), errorMsg, mDevice.icon()); } } @@ -172,7 +172,7 @@ void MenuDiskItem::onUnmounted(Solid::ErrorType error, QVariant resultData, cons else { QString errorMsg = tr("Unmounting of \"%1\" failed: %2"); - errorMsg = errorMsg.arg(mDevice.description()).arg(resultData.toString()); + errorMsg = errorMsg.arg(mDevice.description(), resultData.toString()); LXQt::Notification::notify(tr("Removable media/devices manager"), errorMsg, mDevice.icon()); } } diff --git a/plugin-mount/popup.cpp b/plugin-mount/popup.cpp index 66d34db3a..20720266f 100644 --- a/plugin-mount/popup.cpp +++ b/plugin-mount/popup.cpp @@ -29,7 +29,6 @@ #include "popup.h" #include "../panel/ilxqtpanelplugin.h" -#include #include #include #include @@ -61,7 +60,7 @@ Popup::Popup(ILXQtPanelPlugin * plugin, QWidget* parent): setObjectName(QStringLiteral("LXQtMountPopup")); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setLayout(new QVBoxLayout(this)); - layout()->setMargin(0); + layout()->setContentsMargins(QMargins()); setAttribute(Qt::WA_AlwaysShowToolTips); diff --git a/plugin-qeyes/qeyes.cpp b/plugin-qeyes/qeyes.cpp index f147f8f0b..83df9612d 100644 --- a/plugin-qeyes/qeyes.cpp +++ b/plugin-qeyes/qeyes.cpp @@ -43,7 +43,6 @@ QEyesPlugin::QEyesPlugin(const ILXQtPanelPluginStartupInfo &startupInfo) : w0 = new QWidget(); l = new QVBoxLayout(); l->setSpacing(0); - l->setMargin(0); l->setContentsMargins (0, 0, 0, 0); w0->setLayout(l); diff --git a/plugin-qeyes/qeyesconfigdialog.cpp b/plugin-qeyes/qeyesconfigdialog.cpp index 1ebfd6124..c0e1c2025 100644 --- a/plugin-qeyes/qeyesconfigdialog.cpp +++ b/plugin-qeyes/qeyesconfigdialog.cpp @@ -80,14 +80,19 @@ void QEyesConfigDialog::showEvent(QShowEvent *) { QStringLiteral("2")).toInt(); old_type_eyes = _settings->value(QStringLiteral("eye_type"), QEyesPlugin::internalEye).toString(); + buildList(); + bool found = false; - for (const auto &key : types.keys()) { - if (old_type_eyes == types[key]) { + for (const auto &item : std::as_const(types)) + { + if (old_type_eyes == item) + { found = true; break; } } + if (!found) old_type_eyes = QEyesPlugin::internalEye; @@ -96,8 +101,11 @@ void QEyesConfigDialog::showEvent(QShowEvent *) { typesWidget->clear(); typesWidget->addItem(tr("QEyes default")); - for (const auto &key: types.keys()) - typesWidget->addItem(key); + + for (auto it = types.constBegin(), end = types.constEnd(); it != end; it++) + { + typesWidget->addItem(it.key()); + } resetValue(); @@ -107,11 +115,14 @@ void QEyesConfigDialog::showEvent(QShowEvent *) { numEyesWidget->blockSignals(false); } -void QEyesConfigDialog::resetValue() { +void QEyesConfigDialog::resetValue() +{ int actIndex = 0; int c = 1; // 0 is - for (const auto &key : types.keys()) { - if (old_type_eyes == types[key]) + + for (const auto &item : std::as_const(types)) + { + if (old_type_eyes == item) actIndex = c; c++; } diff --git a/plugin-qeyes/qeyesimagewidget.cpp b/plugin-qeyes/qeyesimagewidget.cpp index 6cc5cd9f8..c1596bff3 100644 --- a/plugin-qeyes/qeyesimagewidget.cpp +++ b/plugin-qeyes/qeyesimagewidget.cpp @@ -32,16 +32,21 @@ #include "qeyesimagewidget.h" -bool ImageStretcher::load(QString fn) { - if (fn.toLower().endsWith(QString::fromUtf8(".svg"))) { +bool ImageStretcher::load(const QString& fn) +{ + if (fn.endsWith(QString::fromUtf8(".svg"), Qt::CaseInsensitive)) + { svg = true; if (!svgrender.load(fn)) return false; - } else { + } + else + { if (!origImage.load(fn)) return false; svg = false; } + stretchedImage = QPixmap(); return true; } diff --git a/plugin-qeyes/qeyesimagewidget.h b/plugin-qeyes/qeyesimagewidget.h index d0b6bf019..e3c284d96 100644 --- a/plugin-qeyes/qeyesimagewidget.h +++ b/plugin-qeyes/qeyesimagewidget.h @@ -30,7 +30,7 @@ class ImageStretcher { QSvgRenderer svgrender; QPixmap origImage, stretchedImage; public: - bool load(QString fn); + bool load(const QString &fn); QPixmap &getImage(int w, int h); int origWidth(); int origHeight(); diff --git a/plugin-qeyes/qeyeswidget.cpp b/plugin-qeyes/qeyeswidget.cpp index 9db035475..4b9c7f023 100644 --- a/plugin-qeyes/qeyeswidget.cpp +++ b/plugin-qeyes/qeyeswidget.cpp @@ -53,7 +53,7 @@ void QAbstractEyesWidget::leaveEvent(QEvent *) { timer.start(); } -void QAbstractEyesWidget::enterEvent(QEvent *) { +void QAbstractEyesWidget::enterEvent(QEnterEvent *) { timer.stop(); } diff --git a/plugin-qeyes/qeyeswidget.h b/plugin-qeyes/qeyeswidget.h index 85118dafe..41f49dabe 100644 --- a/plugin-qeyes/qeyeswidget.h +++ b/plugin-qeyes/qeyeswidget.h @@ -44,7 +44,7 @@ private slots: private: void leaveEvent(QEvent *) override; - void enterEvent(QEvent *) override; + void enterEvent(QEnterEvent *) override; void mouseMoveEvent(QMouseEvent *) override; protected: diff --git a/plugin-quicklaunch/CMakeLists.txt b/plugin-quicklaunch/CMakeLists.txt index dd48bcf4d..eb2e92e0e 100644 --- a/plugin-quicklaunch/CMakeLists.txt +++ b/plugin-quicklaunch/CMakeLists.txt @@ -15,7 +15,7 @@ set(SOURCES ) set(LIBRARIES - Qt5Xdg + Qt6Xdg ) include_directories( diff --git a/plugin-quicklaunch/lxqtquicklaunch.cpp b/plugin-quicklaunch/lxqtquicklaunch.cpp index ae2bf2f49..ab867d970 100644 --- a/plugin-quicklaunch/lxqtquicklaunch.cpp +++ b/plugin-quicklaunch/lxqtquicklaunch.cpp @@ -202,7 +202,9 @@ void LXQtQuickLaunch::dropEvent(QDropEvent *e) } const auto & urls = e->mimeData()->urls(); - for (const QUrl &url : QSet{urls.cbegin(), urls.cend()}) + const QSet uniqueUrls{urls.cbegin(), urls.cend()}; + + for (const QUrl &url : uniqueUrls) { QString fileName(url.isLocalFile() ? url.toLocalFile() : url.url()); QFileInfo fi(fileName); diff --git a/plugin-quicklaunch/quicklaunchbutton.cpp b/plugin-quicklaunch/quicklaunchbutton.cpp index 7dd0945e1..9d1630fcf 100644 --- a/plugin-quicklaunch/quicklaunchbutton.cpp +++ b/plugin-quicklaunch/quicklaunchbutton.cpp @@ -118,7 +118,7 @@ void QuickLaunchButton::this_customContextMenuRequested(const QPoint & /*pos*/) mMoveRightAct->setEnabled(!mPlugin->panel()->isLocked() && panel && panel->indexOfButton(this) < panel->countOfButtons() - 1); mDeleteAct->setEnabled(!mPlugin->panel()->isLocked()); mPlugin->willShowWindow(mMenu); - mMenu->popup(mPlugin->panel()->calculatePopupWindowPos(mapToGlobal({0, 0}), mMenu->sizeHint()).topLeft()); + mMenu->popup(mPlugin->panel()->calculatePopupWindowPos(mapToGlobal(QPoint(0, 0)), mMenu->sizeHint()).topLeft()); } @@ -132,7 +132,7 @@ void QuickLaunchButton::mousePressEvent(QMouseEvent *e) { if (e->button() == Qt::LeftButton && e->modifiers() == Qt::ControlModifier) { - mDragStart = e->pos(); + mDragStart = e->position().toPoint(); return; } @@ -147,7 +147,7 @@ void QuickLaunchButton::mouseMoveEvent(QMouseEvent *e) return; } - if ((e->pos() - mDragStart).manhattanLength() < QApplication::startDragDistance()) + if ((e->position().toPoint() - mDragStart).manhattanLength() < QApplication::startDragDistance()) { return; } diff --git a/plugin-showdesktop/CMakeLists.txt b/plugin-showdesktop/CMakeLists.txt index bf69d2b67..031c90e11 100644 --- a/plugin-showdesktop/CMakeLists.txt +++ b/plugin-showdesktop/CMakeLists.txt @@ -11,7 +11,7 @@ set(SOURCES set(LIBRARIES ${LIBRARIES} lxqt-globalkeys - Qt5Xdg + Qt6Xdg ) BUILD_LXQT_PLUGIN(${PLUGIN}) diff --git a/plugin-showdesktop/showdesktop.cpp b/plugin-showdesktop/showdesktop.cpp index 1733489d2..fb69f6067 100644 --- a/plugin-showdesktop/showdesktop.cpp +++ b/plugin-showdesktop/showdesktop.cpp @@ -26,15 +26,15 @@ * END_COMMON_COPYRIGHT_HEADER */ #include -#include #include #include #include -#include -#include #include "showdesktop.h" #include "../panel/pluginsettings.h" +#include "../panel/lxqtpanelapplication.h" +#include "../panel/backends/ilxqttaskbarabstractbackend.h" + #define DEFAULT_SHORTCUT "Control+Alt+D" ShowDesktop::ShowDesktop(const ILXQtPanelPluginStartupInfo &startupInfo) : @@ -70,7 +70,9 @@ void ShowDesktop::shortcutRegistered() void ShowDesktop::toggleShowingDesktop() { - KWindowSystem::setShowingDesktop(!KWindowSystem::showingDesktop()); + LXQtPanelApplication *a = reinterpret_cast(qApp); + auto wmBackend = a->getWMBackend(); + wmBackend->showDesktop(!wmBackend->isShowingDesktop()); } #undef DEFAULT_SHORTCUT diff --git a/plugin-statusnotifier/CMakeLists.txt b/plugin-statusnotifier/CMakeLists.txt index d12a0f051..76882bc35 100644 --- a/plugin-statusnotifier/CMakeLists.txt +++ b/plugin-statusnotifier/CMakeLists.txt @@ -1,8 +1,8 @@ set(PLUGIN "statusnotifier") -find_package(dbusmenu-qt5 REQUIRED) -find_package(Qt5 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Concurrent) +find_package(dbusmenu-lxqt REQUIRED) +find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Concurrent) set(HEADERS statusnotifier.h @@ -32,7 +32,7 @@ set(UIS statusnotifierconfiguration.ui ) -qt5_add_dbus_adaptor(DBUS_SOURCES +qt6_add_dbus_adaptor(DBUS_SOURCES org.kde.StatusNotifierItem.xml statusnotifieriteminterface.h StatusNotifierItemInterface @@ -43,8 +43,8 @@ set_source_files_properties(${DBUS_SOURCES} PROPERTIES SKIP_AUTOGEN ON) list(APPEND SOURCES "${DBUS_SOURCES}") set(LIBRARIES - dbusmenu-qt5 - Qt5::Concurrent + dbusmenu-lxqt + Qt6::Concurrent ) BUILD_LXQT_PLUGIN(${PLUGIN}) diff --git a/plugin-statusnotifier/statusnotifierbutton.cpp b/plugin-statusnotifier/statusnotifierbutton.cpp index 2f6a5e433..5cd90bfed 100644 --- a/plugin-statusnotifier/statusnotifierbutton.cpp +++ b/plugin-statusnotifier/statusnotifierbutton.cpp @@ -30,7 +30,7 @@ #include #include -#include +#include #include "../panel/ilxqtpanelplugin.h" #include "sniasync.h" #include diff --git a/plugin-statusnotifier/statusnotifierwidget.cpp b/plugin-statusnotifier/statusnotifierwidget.cpp index d71cca731..2ce89d3a7 100644 --- a/plugin-statusnotifier/statusnotifierwidget.cpp +++ b/plugin-statusnotifier/statusnotifierwidget.cpp @@ -96,7 +96,7 @@ void StatusNotifierWidget::leaveEvent(QEvent * /*event*/) mHideTimer.start(); } -void StatusNotifierWidget::enterEvent(QEvent * /*event*/) +void StatusNotifierWidget::enterEvent(QEnterEvent * /*event*/) { mHideTimer.stop(); } @@ -173,7 +173,7 @@ void StatusNotifierWidget::itemRemoved(const QString &serviceAndPath) if (mShowBtn->isVisible() || mForceVisible) { // hide mShowBtn if no (auto-)hidden item remains bool showBtn = false; - for (const auto &name : qAsConst(mItemTitles)) + for (const auto &name : std::as_const(mItemTitles)) { if (mAutoHideList.contains(name) || mHideList.contains(name)) { diff --git a/plugin-statusnotifier/statusnotifierwidget.h b/plugin-statusnotifier/statusnotifierwidget.h index 1711eb6f4..379722e82 100644 --- a/plugin-statusnotifier/statusnotifierwidget.h +++ b/plugin-statusnotifier/statusnotifierwidget.h @@ -57,7 +57,7 @@ public slots: protected: void leaveEvent(QEvent *event) override; - void enterEvent(QEvent *event) override; + void enterEvent(QEnterEvent *event) override; private: ILXQtPanelPlugin *mPlugin; diff --git a/plugin-sysstat/CMakeLists.txt b/plugin-sysstat/CMakeLists.txt index 6cb28e67d..af013b9f0 100644 --- a/plugin-sysstat/CMakeLists.txt +++ b/plugin-sysstat/CMakeLists.txt @@ -1,6 +1,6 @@ set(PLUGIN "sysstat") -find_package(SysStat-Qt5 REQUIRED) +find_package(SysStat-Qt6 REQUIRED) set(HEADERS lxqtsysstat.h @@ -21,6 +21,6 @@ set(UIS lxqtsysstatcolours.ui ) -set(LIBRARIES sysstat-qt5) +set(LIBRARIES sysstat-qt6) BUILD_LXQT_PLUGIN(${PLUGIN}) diff --git a/plugin-sysstat/lxqtsysstatutils.cpp b/plugin-sysstat/lxqtsysstatutils.cpp index fe9bc5ca6..b053b4eef 100644 --- a/plugin-sysstat/lxqtsysstatutils.cpp +++ b/plugin-sysstat/lxqtsysstatutils.cpp @@ -25,7 +25,7 @@ * * END_COMMON_COPYRIGHT_HEADER */ -#include +#include #include #include "lxqtsysstatutils.h" @@ -44,13 +44,14 @@ QString netSpeedToString(int value) return QStringLiteral("%1 %2B/s").arg(1 << (value % 10)).arg(prefix); } -int netSpeedFromString(QString value) +int netSpeedFromString(const QStringView& value) { - QRegExp re(QStringLiteral("^(\\d+) ([kMG])B/s$")); - if (re.exactMatch(value)) + static QRegularExpression re(QStringLiteral("^(\\d+) ([kMG])B/s$")); + QRegularExpressionMatch match = re.matchView(value); + if (match.hasMatch()) { int shift = 0; - switch (re.cap(2).at(0).toLatin1()) + switch (match.capturedView(2).at(0).toLatin1()) { case 'k': shift = 10; @@ -65,7 +66,7 @@ int netSpeedFromString(QString value) break; } - return qCeil(qLn(re.cap(1).toInt()) / qLn(2.)) + shift; + return qCeil(qLn(match.capturedView(1).toInt()) / qLn(2.)) + shift; } return 0; diff --git a/plugin-sysstat/lxqtsysstatutils.h b/plugin-sysstat/lxqtsysstatutils.h index e83aee767..4fc7fef90 100644 --- a/plugin-sysstat/lxqtsysstatutils.h +++ b/plugin-sysstat/lxqtsysstatutils.h @@ -34,7 +34,7 @@ namespace PluginSysStat { QString netSpeedToString(int value); -int netSpeedFromString(QString value); +int netSpeedFromString(const QStringView &value); } diff --git a/plugin-taskbar/CMakeLists.txt b/plugin-taskbar/CMakeLists.txt index 4f7b34dc3..74a00d6e6 100644 --- a/plugin-taskbar/CMakeLists.txt +++ b/plugin-taskbar/CMakeLists.txt @@ -7,6 +7,8 @@ set(HEADERS lxqttaskbarplugin.h lxqttaskgroup.h lxqtgrouppopup.h + + lxqttaskbarproxymodel.h ) set(SOURCES @@ -16,6 +18,8 @@ set(SOURCES lxqttaskbarplugin.cpp lxqttaskgroup.cpp lxqtgrouppopup.cpp + + lxqttaskbarproxymodel.cpp ) set(UIS @@ -25,7 +29,7 @@ set(UIS set(LIBRARIES lxqt lxqt-globalkeys - Qt5Xdg + Qt6Xdg ) BUILD_LXQT_PLUGIN(${PLUGIN}) diff --git a/plugin-taskbar/lxqtgrouppopup.cpp b/plugin-taskbar/lxqtgrouppopup.cpp index 822416865..a71ca2b41 100644 --- a/plugin-taskbar/lxqtgrouppopup.cpp +++ b/plugin-taskbar/lxqtgrouppopup.cpp @@ -29,6 +29,8 @@ * END_COMMON_COPYRIGHT_HEADER */ #include "lxqtgrouppopup.h" +#include "lxqttaskgroup.h" + #include #include #include @@ -55,7 +57,7 @@ LXQtGroupPopup::LXQtGroupPopup(LXQtTaskGroup *group): setLayout(new QVBoxLayout); layout()->setSpacing(3); - layout()->setMargin(3); + layout()->setContentsMargins(3, 3, 3, 3); connect(&mCloseTimer, &QTimer::timeout, this, &LXQtGroupPopup::closeTimerSlot); mCloseTimer.setSingleShot(true); @@ -93,14 +95,14 @@ void LXQtGroupPopup::dropEvent(QDropEvent *event) for (int i = 0; i < oldIndex && newIndex == -1; i++) { QWidget *w = layout()->itemAt(i)->widget(); - if (w && w->pos().y() + w->height() / 2 > event->pos().y()) + if (w && w->pos().y() + w->height() / 2 > event->position().y()) newIndex = i; } const int size = layout()->count(); for (int i = size - 1; i > oldIndex && newIndex == -1; i--) { QWidget *w = layout()->itemAt(i)->widget(); - if (w && w->pos().y() + w->height() / 2 < event->pos().y()) + if (w && w->pos().y() + w->height() / 2 < event->position().y()) newIndex = i; } @@ -137,7 +139,7 @@ void LXQtGroupPopup::leaveEvent(QEvent * /*event*/) /************************************************ * ************************************************/ -void LXQtGroupPopup::enterEvent(QEvent * /*event*/) +void LXQtGroupPopup::enterEvent(QEnterEvent * /*event*/) { mCloseTimer.stop(); } @@ -164,6 +166,16 @@ void LXQtGroupPopup::show() QFrame::show(); } +int LXQtGroupPopup::indexOf(LXQtTaskButton *button) +{ + return layout()->indexOf(button); +} + +void LXQtGroupPopup::addButton(LXQtTaskButton *button) +{ + layout()->addWidget(button); +} + void LXQtGroupPopup::closeTimerSlot() { bool button_has_dnd_hover = false; diff --git a/plugin-taskbar/lxqtgrouppopup.h b/plugin-taskbar/lxqtgrouppopup.h index 515236c79..5db42339e 100644 --- a/plugin-taskbar/lxqtgrouppopup.h +++ b/plugin-taskbar/lxqtgrouppopup.h @@ -37,9 +37,8 @@ #include #include -#include "lxqttaskbutton.h" -#include "lxqttaskgroup.h" -#include "lxqttaskbar.h" +class LXQtTaskButton; +class LXQtTaskGroup; class LXQtGroupPopup: public QFrame { @@ -53,11 +52,11 @@ class LXQtGroupPopup: public QFrame void show(); // Layout - int indexOf(LXQtTaskButton *button) { return layout()->indexOf(button); } + int indexOf(LXQtTaskButton *button); int count() { return layout()->count(); } QLayoutItem * itemAt(int i) { return layout()->itemAt(i); } int spacing() { return layout()->spacing(); } - void addButton(LXQtTaskButton* button) { layout()->addWidget(button); } + void addButton(LXQtTaskButton* button); void removeWidget(QWidget *button) { layout()->removeWidget(button); } protected: @@ -65,7 +64,7 @@ class LXQtGroupPopup: public QFrame void dragLeaveEvent(QDragLeaveEvent *event); void dropEvent(QDropEvent * event); void leaveEvent(QEvent * event); - void enterEvent(QEvent * event); + void enterEvent(QEnterEvent *event); void paintEvent(QPaintEvent * event); void closeTimerSlot(); diff --git a/plugin-taskbar/lxqttaskbar.cpp b/plugin-taskbar/lxqttaskbar.cpp index 0138b4f79..43090c396 100644 --- a/plugin-taskbar/lxqttaskbar.cpp +++ b/plugin-taskbar/lxqttaskbar.cpp @@ -28,6 +28,8 @@ * * END_COMMON_COPYRIGHT_HEADER */ +#include "lxqttaskbar.h" + #include #include #include @@ -37,15 +39,19 @@ #include #include #include -#include #include +#include "ilxqtpanelplugin.h" +#include "pluginsettings.h" + #include #include -#include -#include "lxqttaskbar.h" #include "lxqttaskgroup.h" +#include "../panel/pluginsettings.h" + +#include "../panel/backends/ilxqttaskbarabstractbackend.h" +#include "../panel/lxqtpanelapplication.h" using namespace LXQt; @@ -73,12 +79,13 @@ LXQtTaskBar::LXQtTaskBar(ILXQtPanelPlugin *plugin, QWidget *parent) : mWheelDeltaThreshold(300), mPlugin(plugin), mPlaceHolder(new QWidget(this)), - mStyle(new LeftAlignedTextStyle()) + mStyle(new LeftAlignedTextStyle()), + mBackend(nullptr) { setStyle(mStyle); mLayout = new LXQt::GridLayout(this); setLayout(mLayout); - mLayout->setMargin(0); + mLayout->setContentsMargins(QMargins()); mLayout->setStretch(LXQt::GridLayout::StretchHorizontal | LXQt::GridLayout::StretchVertical); realign(); @@ -87,16 +94,26 @@ LXQtTaskBar::LXQtTaskBar(ILXQtPanelPlugin *plugin, QWidget *parent) : mPlaceHolder->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); mLayout->addWidget(mPlaceHolder); + // Get backend + LXQtPanelApplication *a = static_cast(qApp); + mBackend = a->getWMBackend(); + QTimer::singleShot(0, this, &LXQtTaskBar::settingsChanged); setAcceptDrops(true); connect(mSignalMapper, &QSignalMapper::mappedInt, this, &LXQtTaskBar::activateTask); QTimer::singleShot(0, this, &LXQtTaskBar::registerShortcuts); - connect(KX11Extras::self(), static_cast(&KX11Extras::windowChanged) - , this, &LXQtTaskBar::onWindowChanged); - connect(KX11Extras::self(), &KX11Extras::windowAdded, this, &LXQtTaskBar::onWindowAdded); - connect(KX11Extras::self(), &KX11Extras::windowRemoved, this, &LXQtTaskBar::onWindowRemoved); + connect(mBackend, &ILXQtTaskbarAbstractBackend::windowPropertyChanged, this, &LXQtTaskBar::onWindowChanged); + connect(mBackend, &ILXQtTaskbarAbstractBackend::windowAdded, this, &LXQtTaskBar::onWindowAdded); + connect(mBackend, &ILXQtTaskbarAbstractBackend::windowRemoved, this, &LXQtTaskBar::onWindowRemoved); + + // Consider already fetched windows + const auto initialWindows = mBackend->getCurrentWindows(); + for(WId windowId : initialWindows) + { + onWindowAdded(windowId); + } } /************************************************ @@ -107,45 +124,6 @@ LXQtTaskBar::~LXQtTaskBar() delete mStyle; } -/************************************************ - - ************************************************/ -bool LXQtTaskBar::acceptWindow(WId window) const -{ - QFlags ignoreList; - ignoreList |= NET::DesktopMask; - ignoreList |= NET::DockMask; - ignoreList |= NET::SplashMask; - ignoreList |= NET::ToolbarMask; - ignoreList |= NET::MenuMask; - ignoreList |= NET::PopupMenuMask; - ignoreList |= NET::NotificationMask; - - KWindowInfo info(window, NET::WMWindowType | NET::WMState, NET::WM2TransientFor); - if (!info.valid()) - return false; - - if (NET::typeMatchesMask(info.windowType(NET::AllTypesMask), ignoreList)) - return false; - - if (info.state() & NET::SkipTaskbar) - return false; - - // WM_TRANSIENT_FOR hint not set - normal window - WId transFor = info.transientFor(); - if (transFor == 0 || transFor == window || transFor == (WId) QX11Info::appRootWindow()) - return true; - - info = KWindowInfo(transFor, NET::WMWindowType); - - QFlags normalFlag; - normalFlag |= NET::NormalMask; - normalFlag |= NET::DialogMask; - normalFlag |= NET::UtilityMask; - - return !NET::typeMatchesMask(info.windowType(NET::AllTypesMask), normalFlag); -} - /************************************************ ************************************************/ @@ -154,7 +132,7 @@ void LXQtTaskBar::dragEnterEvent(QDragEnterEvent* event) if (event->mimeData()->hasFormat(LXQtTaskGroup::mimeDataFormat())) { event->acceptProposedAction(); - buttonMove(nullptr, qobject_cast(event->source()), event->pos()); + buttonMove(nullptr, qobject_cast(event->source()), event->position().toPoint()); } else event->ignore(); QWidget::dragEnterEvent(event); @@ -166,7 +144,7 @@ void LXQtTaskBar::dragEnterEvent(QDragEnterEvent* event) void LXQtTaskBar::dragMoveEvent(QDragMoveEvent * event) { //we don't get any dragMoveEvents if dragEnter wasn't accepted - buttonMove(nullptr, qobject_cast(event->source()), event->pos()); + buttonMove(nullptr, qobject_cast(event->source()), event->position().toPoint()); QWidget::dragMoveEvent(event); } @@ -271,7 +249,7 @@ void LXQtTaskBar::groupBecomeEmptySlot() void LXQtTaskBar::addWindow(WId window) { // If grouping disabled group behaves like regular button - const QString group_id = mGroupingEnabled ? QString::fromUtf8(KWindowInfo(window, NET::Properties(), NET::WM2WindowClass).windowClassClass()) : QString::number(window); + const QString group_id = mGroupingEnabled ? mBackend->getWindowClass(window) : QString::number(window); LXQtTaskGroup *group = nullptr; auto i_group = mKnownWindows.find(window); @@ -310,7 +288,7 @@ void LXQtTaskBar::addWindow(WId window) if (mUngroupedNextToExisting) { - const QString window_class = QString::fromUtf8(KWindowInfo(window, NET::Properties(), NET::WM2WindowClass).windowClassClass()); + const QString window_class = mBackend->getWindowClass(window); int src_index = mLayout->count() - 1; int dst_index = src_index; for (int i = mLayout->count() - 2; 0 <= i; --i) @@ -318,7 +296,7 @@ void LXQtTaskBar::addWindow(WId window) LXQtTaskGroup * current_group = qobject_cast(mLayout->itemAt(i)->widget()); if (nullptr != current_group) { - const QString current_class = QString::fromUtf8(KWindowInfo((current_group->groupName()).toUInt(), NET::Properties(), NET::WM2WindowClass).windowClassClass()); + const QString current_class = mBackend->getWindowClass(current_group->groupName().toUInt()); if(current_class == window_class) { dst_index = i + 1; @@ -352,43 +330,14 @@ auto LXQtTaskBar::removeWindow(windowMap_t::iterator pos) -> windowMap_t::iterat /************************************************ ************************************************/ -void LXQtTaskBar::refreshTaskList() -{ - QList new_list; - // Just add new windows to groups, deleting is up to the groups - const auto wnds = KX11Extras::stackingOrder(); - for (auto const wnd: wnds) - { - if (acceptWindow(wnd)) - { - new_list << wnd; - addWindow(wnd); - } - } - - //emulate windowRemoved if known window not reported by KWindowSystem - for (auto i = mKnownWindows.begin(), i_e = mKnownWindows.end(); i != i_e; ) - { - if (0 > new_list.indexOf(i.key())) - { - i = removeWindow(i); - } else - ++i; - } - - refreshPlaceholderVisibility(); -} - -/************************************************ - - ************************************************/ -void LXQtTaskBar::onWindowChanged(WId window, NET::Properties prop, NET::Properties2 prop2) +void LXQtTaskBar::onWindowChanged(WId window, int prop) { auto i = mKnownWindows.find(window); if (mKnownWindows.end() != i) { - if (!(*i)->onWindowChanged(window, prop, prop2) && acceptWindow(window)) - { // window is removed from a group because of class change, so we should add it again + if (!(*i)->onWindowChanged(window, LXQtTaskBarWindowProperty(prop))) + { + // window is removed from a group because of class change, so we should add it again addWindow(window); } } @@ -397,7 +346,7 @@ void LXQtTaskBar::onWindowChanged(WId window, NET::Properties prop, NET::Propert void LXQtTaskBar::onWindowAdded(WId window) { auto const pos = mKnownWindows.find(window); - if (mKnownWindows.end() == pos && acceptWindow(window)) + if (mKnownWindows.end() == pos) addWindow(window); } @@ -523,7 +472,8 @@ void LXQtTaskBar::settingsChanged() if (iconByClassOld != mIconByClass) emit iconByClassChanged(); - refreshTaskList(); + mBackend->reloadWindows(); + refreshPlaceholderVisibility(); } /************************************************ @@ -583,6 +533,11 @@ void LXQtTaskBar::realign() emit refreshIconGeometry(); } +ILXQtPanel *LXQtTaskBar::panel() const +{ + return mPlugin->panel(); +} + /************************************************ ************************************************/ diff --git a/plugin-taskbar/lxqttaskbar.h b/plugin-taskbar/lxqttaskbar.h index 5b2e79e7a..9f94a2958 100644 --- a/plugin-taskbar/lxqttaskbar.h +++ b/plugin-taskbar/lxqttaskbar.h @@ -32,29 +32,32 @@ #ifndef LXQTTASKBAR_H #define LXQTTASKBAR_H -#include "../panel/ilxqtpanel.h" -#include "../panel/ilxqtpanelplugin.h" -#include "lxqttaskbarconfiguration.h" -#include "lxqttaskgroup.h" -#include "lxqttaskbutton.h" - #include #include #include -#include + #include "../panel/ilxqtpanel.h" -#include -#include -#include + +class ILXQtPanel; +class ILXQtPanelPlugin; class QSignalMapper; -class LXQtTaskButton; -class ElidedButtonStyle; + +class LXQtTaskGroup; + +class LeftAlignedTextStyle; + +class ILXQtTaskbarAbstractBackend; namespace LXQt { class GridLayout; } +namespace GlobalKeyShortcut +{ +class Action; +} + class LXQtTaskBar : public QFrame { Q_OBJECT @@ -79,9 +82,12 @@ class LXQtTaskBar : public QFrame bool isIconByClass() const { return mIconByClass; } int wheelEventsAction() const { return mWheelEventsAction; } int wheelDeltaThreshold() const { return mWheelDeltaThreshold; } - inline ILXQtPanel * panel() const { return mPlugin->panel(); } + + ILXQtPanel * panel() const; inline ILXQtPanelPlugin * plugin() const { return mPlugin; } + inline ILXQtTaskbarAbstractBackend *getBackend() const { return mBackend; } + public slots: void settingsChanged(); @@ -98,13 +104,14 @@ public slots: virtual void dragMoveEvent(QDragMoveEvent * event); private slots: - void refreshTaskList(); void refreshButtonRotation(); void refreshPlaceholderVisibility(); void groupBecomeEmptySlot(); - void onWindowChanged(WId window, NET::Properties prop, NET::Properties2 prop2); + + void onWindowChanged(WId window, int prop); void onWindowAdded(WId window); void onWindowRemoved(WId window); + void registerShortcuts(); void shortcutRegistered(); void activateTask(int pos); @@ -141,7 +148,6 @@ private slots: int mWheelEventsAction; int mWheelDeltaThreshold; - bool acceptWindow(WId window) const; void setButtonStyle(Qt::ToolButtonStyle buttonStyle); void wheelEvent(QWheelEvent* event); @@ -151,6 +157,8 @@ private slots: ILXQtPanelPlugin *mPlugin; QWidget *mPlaceHolder; LeftAlignedTextStyle *mStyle; + + ILXQtTaskbarAbstractBackend *mBackend; }; #endif // LXQTTASKBAR_H diff --git a/plugin-taskbar/lxqttaskbarconfiguration.cpp b/plugin-taskbar/lxqttaskbarconfiguration.cpp index 267d20e8c..0dd528e51 100644 --- a/plugin-taskbar/lxqttaskbarconfiguration.cpp +++ b/plugin-taskbar/lxqttaskbarconfiguration.cpp @@ -29,7 +29,9 @@ #include "lxqttaskbarconfiguration.h" #include "ui_lxqttaskbarconfiguration.h" -#include + +#include "../panel/lxqtpanelapplication.h" +#include "../panel/backends/ilxqttaskbarabstractbackend.h" LXQtTaskbarConfiguration::LXQtTaskbarConfiguration(PluginSettings *settings, QWidget *parent): LXQtPanelPluginConfigDialog(settings, parent), @@ -52,11 +54,14 @@ LXQtTaskbarConfiguration::LXQtTaskbarConfiguration(PluginSettings *settings, QWi ui->wheelEventsActionCB->addItem(tr("Scroll up to move to next desktop, down to previous"), 4); ui->wheelEventsActionCB->addItem(tr("Scroll up to move to previous desktop, down to next"), 5); + LXQtPanelApplication *a = reinterpret_cast(qApp); + auto wmBackend = a->getWMBackend(); + ui->showDesktopNumCB->addItem(tr("Current"), 0); //Note: in KWindowSystem desktops are numbered from 1..N - const int desk_cnt = KX11Extras::numberOfDesktops(); + const int desk_cnt = wmBackend->getWorkspacesCount(); for (int i = 1; desk_cnt >= i; ++i) - ui->showDesktopNumCB->addItem(QString(QStringLiteral("%1 - %2")).arg(i).arg(KX11Extras::desktopName(i)), i); + ui->showDesktopNumCB->addItem(QString(QStringLiteral("%1 - %2")).arg(i).arg(wmBackend->getWorkspaceName(i)), i); loadSettings(); ui->ungroupedNextToExistingCB->setEnabled(!(ui->groupingGB->isChecked())); diff --git a/plugin-taskbar/lxqttaskbarconfiguration.h b/plugin-taskbar/lxqttaskbarconfiguration.h index e559508b7..930e9f441 100644 --- a/plugin-taskbar/lxqttaskbarconfiguration.h +++ b/plugin-taskbar/lxqttaskbarconfiguration.h @@ -29,8 +29,8 @@ #define LXQTTASKBARCONFIGURATION_H #include "../panel/lxqtpanelpluginconfigdialog.h" -#include "../panel/pluginsettings.h" -#include + +class PluginSettings; namespace Ui { class LXQtTaskbarConfiguration; diff --git a/plugin-taskbar/lxqttaskbarplugin.cpp b/plugin-taskbar/lxqttaskbarplugin.cpp index 51dc41456..759e6db46 100644 --- a/plugin-taskbar/lxqttaskbarplugin.cpp +++ b/plugin-taskbar/lxqttaskbarplugin.cpp @@ -28,13 +28,16 @@ #include "lxqttaskbarplugin.h" +#include "lxqttaskbar.h" + +#include "lxqttaskbarconfiguration.h" + LXQtTaskBarPlugin::LXQtTaskBarPlugin(const ILXQtPanelPluginStartupInfo &startupInfo): QObject(), ILXQtPanelPlugin(startupInfo) { mTaskBar = new LXQtTaskBar(this); - } @@ -43,11 +46,18 @@ LXQtTaskBarPlugin::~LXQtTaskBarPlugin() delete mTaskBar; } +QWidget *LXQtTaskBarPlugin::widget() { return mTaskBar; } + QDialog *LXQtTaskBarPlugin::configureDialog() { return new LXQtTaskbarConfiguration(settings()); } +void LXQtTaskBarPlugin::settingsChanged() +{ + mTaskBar->settingsChanged(); +} + void LXQtTaskBarPlugin::realign() { mTaskBar->realign(); diff --git a/plugin-taskbar/lxqttaskbarplugin.h b/plugin-taskbar/lxqttaskbarplugin.h index 9c3076990..9bc34cf8e 100644 --- a/plugin-taskbar/lxqttaskbarplugin.h +++ b/plugin-taskbar/lxqttaskbarplugin.h @@ -29,10 +29,8 @@ #ifndef LXQTTASKBARPLUGIN_H #define LXQTTASKBARPLUGIN_H -#include "../panel/ilxqtpanel.h" -#include "../panel/ilxqtpanelplugin.h" -#include "lxqttaskbar.h" -#include +#include "ilxqtpanelplugin.h" + class LXQtTaskBar; class LXQtTaskBarPlugin : public QObject, public ILXQtPanelPlugin @@ -45,10 +43,10 @@ class LXQtTaskBarPlugin : public QObject, public ILXQtPanelPlugin QString themeId() const { return QStringLiteral("TaskBar"); } virtual Flags flags() const { return HaveConfigDialog | NeedsHandle; } - QWidget *widget() { return mTaskBar; } + QWidget *widget(); QDialog *configureDialog(); - void settingsChanged() { mTaskBar->settingsChanged(); } + void settingsChanged(); void realign(); bool isSeparate() const { return true; } diff --git a/plugin-taskbar/lxqttaskbarproxymodel.cpp b/plugin-taskbar/lxqttaskbarproxymodel.cpp new file mode 100644 index 000000000..fdcdfa4d4 --- /dev/null +++ b/plugin-taskbar/lxqttaskbarproxymodel.cpp @@ -0,0 +1,257 @@ +#include "lxqttaskbarproxymodel.h" + +#include "../panel/backends/ilxqttaskbarabstractbackend.h" + +#include + +LXQtTaskBarProxyModel::LXQtTaskBarProxyModel(QObject *parent) + : QAbstractListModel(parent) + , m_backend(nullptr) + , m_groupByWindowClass(false) +{ + +} + +int LXQtTaskBarProxyModel::rowCount(const QModelIndex &parent) const +{ + return parent.isValid() ? 0 : m_items.count(); +} + +QVariant LXQtTaskBarProxyModel::data(const QModelIndex &idx, int role) const +{ + if (!idx.isValid() || idx.row() >= m_items.count()) + return QVariant(); + + const LXQtTaskBarProxyModelItem& item = m_items.at(idx.row()); + + switch (role) + { + case Qt::DisplayRole: + return item.windows.count() == 1 ? item.windows.first().title : item.windowClass; + default: + break; + } + + return QVariant(); +} + +QIcon LXQtTaskBarProxyModel::getWindowIcon(int itemRow, int windowIdxInGroup, int devicePixels) const +{ + if(!m_backend || itemRow < 0 || itemRow >= m_items.size() || windowIdxInGroup < 0) + return QIcon(); + + const LXQtTaskBarProxyModelItem& item = m_items.at(itemRow); + if(windowIdxInGroup >= item.windows.size()) + return QIcon(); + + const LXQtTaskBarProxyModelWindow& window = item.windows.at(windowIdxInGroup); + return m_backend->getApplicationIcon(window.windowId, devicePixels); +} + +void LXQtTaskBarProxyModel::onWindowAdded(WId windowId) +{ + QString windowClass = m_backend->getWindowClass(windowId); + bool willAddRow = !m_groupByWindowClass || !hasWindowClass(windowClass); + + if(willAddRow) + { + const int row = m_items.count(); + beginInsertRows(QModelIndex(), row, row); + } + + addWindow_internal(windowId); + + if(willAddRow) + endInsertRows(); +} + +void LXQtTaskBarProxyModel::onWindowRemoved(WId windowId) +{ + int row = -1; + int windowIdxInGroup = -1; + for(int i = 0; i < m_items.count(); i++) + { + windowIdxInGroup = m_items.at(i).indexOfWindow(windowId); + if(windowIdxInGroup != -1) + { + row = i; + break; + } + } + + if(row == -1) + return; + + LXQtTaskBarProxyModelItem& item = m_items[row]; + item.windows.removeAt(windowIdxInGroup); + + if(item.windows.isEmpty()) + { + // Remove the group + beginRemoveRows(QModelIndex(), row, row); + m_items.removeAt(row); + endRemoveRows(); + } +} + +void LXQtTaskBarProxyModel::onWindowPropertyChanged(WId windowId, int prop) +{ + int row = -1; + int windowIdxInGroup = -1; + for(int i = 0; i < m_items.count(); i++) + { + windowIdxInGroup = m_items.at(i).indexOfWindow(windowId); + if(windowIdxInGroup != -1) + { + row = i; + break; + } + } + + if(row == -1) + return; + + LXQtTaskBarProxyModelItem& item = m_items[row]; + LXQtTaskBarProxyModelWindow& window = item.windows[windowIdxInGroup]; + + switch (LXQtTaskBarWindowProperty(prop)) + { + case LXQtTaskBarWindowProperty::Title: + window.title = m_backend->getWindowTitle(window.windowId); + break; + + case LXQtTaskBarWindowProperty::Urgency: + window.demandsAttention = m_backend->applicationDemandsAttention(window.windowId); + break; + + case LXQtTaskBarWindowProperty::WindowClass: + { + // If window class is changed, window won't be part of same group + //TODO: optimize + onWindowRemoved(windowId); + onWindowAdded(windowId); + } + + default: + break; + } + + const QModelIndex idx = index(row); + emit dataChanged(idx, idx, {Qt::DisplayRole, Qt::DecorationRole}); +} + +void LXQtTaskBarProxyModel::addWindow_internal(WId windowId) +{ + LXQtTaskBarProxyModelWindow window; + window.windowId = windowId; + window.title = m_backend->getWindowTitle(window.windowId); + window.demandsAttention = m_backend->applicationDemandsAttention(window.windowId); + + QString windowClass = m_backend->getWindowClass(window.windowId); + + int row = -1; + if(m_groupByWindowClass) + { + // Find existing group + for(int i = 0; i < m_items.count(); i++) + { + if(m_items.at(i).windowClass == windowClass) + { + row = i; + break; + } + } + } + + if(row == -1) + { + // Create new group + LXQtTaskBarProxyModelItem item; + item.windowClass = windowClass; + m_items.append(item); + row = m_items.size() - 1; + } + + // Add window to group + LXQtTaskBarProxyModelItem& item = m_items[row]; + item.windows.append(window); +} + +bool LXQtTaskBarProxyModel::groupByWindowClass() const +{ + return m_groupByWindowClass; +} + +void LXQtTaskBarProxyModel::setGroupByWindowClass(bool newGroupByWindowClass) +{ + if(m_groupByWindowClass == newGroupByWindowClass) + return; + + m_groupByWindowClass = newGroupByWindowClass; + + if(m_backend && !m_items.isEmpty()) + { + beginResetModel(); + + m_items.clear(); + + // Reload current windows + const QVector windows = m_backend->getCurrentWindows(); + m_items.reserve(windows.size()); + + for(WId windowId : windows) + onWindowAdded(windowId); + + m_items.squeeze(); + + endResetModel(); + } + +} + +ILXQtTaskbarAbstractBackend *LXQtTaskBarProxyModel::backend() const +{ + return m_backend; +} + +void LXQtTaskBarProxyModel::setBackend(ILXQtTaskbarAbstractBackend *newBackend) +{ + beginResetModel(); + + m_items.clear(); + + if(m_backend) + { + disconnect(m_backend, &ILXQtTaskbarAbstractBackend::windowAdded, + this, &LXQtTaskBarProxyModel::onWindowAdded); + disconnect(m_backend, &ILXQtTaskbarAbstractBackend::windowRemoved, + this, &LXQtTaskBarProxyModel::onWindowRemoved); + disconnect(m_backend, &ILXQtTaskbarAbstractBackend::windowPropertyChanged, + this, &LXQtTaskBarProxyModel::onWindowPropertyChanged); + } + + m_backend = newBackend; + + if(m_backend) + { + connect(m_backend, &ILXQtTaskbarAbstractBackend::windowAdded, + this, &LXQtTaskBarProxyModel::onWindowAdded); + connect(m_backend, &ILXQtTaskbarAbstractBackend::windowRemoved, + this, &LXQtTaskBarProxyModel::onWindowRemoved); + connect(m_backend, &ILXQtTaskbarAbstractBackend::windowPropertyChanged, + this, &LXQtTaskBarProxyModel::onWindowPropertyChanged); + + // Reload current windows + const QVector windows = m_backend->getCurrentWindows(); + m_items.reserve(windows.size()); + + for(WId windowId : windows) + onWindowAdded(windowId); + + m_items.squeeze(); + } + + m_items.squeeze(); + + endResetModel(); +} diff --git a/plugin-taskbar/lxqttaskbarproxymodel.h b/plugin-taskbar/lxqttaskbarproxymodel.h new file mode 100644 index 000000000..8bbb5ec49 --- /dev/null +++ b/plugin-taskbar/lxqttaskbarproxymodel.h @@ -0,0 +1,100 @@ +#ifndef LXQTTASKBARPROXYMODEL_H +#define LXQTTASKBARPROXYMODEL_H + +#include +#include + +#include "../panel/backends/lxqttaskbartypes.h" + +class ILXQtTaskbarAbstractBackend; + +class LXQtTaskBarProxyModelWindow +{ +public: + LXQtTaskBarProxyModelWindow() = default; + + WId windowId; + QString title; + bool demandsAttention = false; +}; + +// Single window or group +class LXQtTaskBarProxyModelItem +{ +public: + LXQtTaskBarProxyModelItem() = default; + + QVector windows; + QString windowClass; + + inline bool demandsAttention() const + { + for(const LXQtTaskBarProxyModelWindow& w : windows) + { + if(w.demandsAttention) + return true; + } + + return false; + } + + int indexOfWindow(WId windowId) const + { + for(int i = 0; i < windows.size(); i++) + { + if(windows.at(i).windowId == windowId) + return i; + } + + return -1; + } +}; + +class LXQtTaskBarProxyModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit LXQtTaskBarProxyModel(QObject *parent = nullptr); + + // Basic functionality: + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override; + + QIcon getWindowIcon(int itemRow, int windowIdxInGroup, int devicePixels) const; + + ILXQtTaskbarAbstractBackend *backend() const; + void setBackend(ILXQtTaskbarAbstractBackend *newBackend); + + bool groupByWindowClass() const; + void setGroupByWindowClass(bool newGroupByWindowClass); + +private slots: + void onWindowAdded(WId windowId); + void onWindowRemoved(WId windowId); + void onWindowPropertyChanged(WId windowId, int prop); + +private: + void addWindow_internal(WId windowId); + + inline bool hasWindowClass(const QString& windowClass) const + { + for(const LXQtTaskBarProxyModelItem& item : m_items) + { + if(item.windowClass == windowClass) + return true; + } + + return false; + } + +private: + ILXQtTaskbarAbstractBackend *m_backend; + + QVector m_items; + + bool m_groupByWindowClass; +}; + +#endif // LXQTTASKBARPROXYMODEL_H diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index 8c63d4db1..c2e2a0282 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -28,9 +28,10 @@ * END_COMMON_COPYRIGHT_HEADER */ #include "lxqttaskbutton.h" -#include "lxqttaskgroup.h" #include "lxqttaskbar.h" +#include "ilxqtpanelplugin.h" + #include #include @@ -47,17 +48,11 @@ #include #include #include -#include #include -#include "lxqttaskbutton.h" -#include "lxqttaskgroup.h" -#include "lxqttaskbar.h" +#include "../panel/backends/ilxqttaskbarabstractbackend.h" + -#include -// Necessary for closeApplication() -#include -#include bool LXQtTaskButton::sDraggging = false; @@ -82,6 +77,7 @@ void LeftAlignedTextStyle::drawItemText(QPainter * painter, const QRect & rect, ************************************************/ LXQtTaskButton::LXQtTaskButton(const WId window, LXQtTaskBar * taskbar, QWidget *parent) : QToolButton(parent), + mBackend(taskbar->getBackend()), mWindow(window), mUrgencyHint(false), mOrigin(Qt::TopLeftCorner), @@ -115,8 +111,7 @@ LXQtTaskButton::LXQtTaskButton(const WId window, LXQtTaskBar * taskbar, QWidget mWheelDelta = 0; // forget previous wheel deltas }); - setUrgencyHint(NETWinInfo(QX11Info::connection(), mWindow, QX11Info::appRootWindow(), NET::Properties{}, NET::WM2Urgency).urgency() - || KWindowInfo{mWindow, NET::WMState}.hasState(NET::DemandsAttention)); + setUrgencyHint(mBackend->applicationDemandsAttention(mWindow)); connect(LXQt::Settings::globalSettings(), &LXQt::GlobalSettings::iconThemeChanged, this, &LXQtTaskButton::updateIcon); connect(mParentTaskBar, &LXQtTaskBar::iconByClassChanged, this, &LXQtTaskButton::updateIcon); @@ -132,8 +127,7 @@ LXQtTaskButton::~LXQtTaskButton() = default; ************************************************/ void LXQtTaskButton::updateText() { - KWindowInfo info(mWindow, NET::WMVisibleName | NET::WMName); - QString title = info.visibleName().isEmpty() ? info.name() : info.visibleName(); + QString title = mBackend->getWindowTitle(mWindow); setText(title.replace(QStringLiteral("&"), QStringLiteral("&&"))); setToolTip(title); } @@ -146,53 +140,16 @@ void LXQtTaskButton::updateIcon() QIcon ico; if (mParentTaskBar->isIconByClass()) { - ico = XdgIcon::fromTheme(QString::fromUtf8(KWindowInfo{mWindow, NET::Properties(), NET::WM2WindowClass}.windowClassClass()).toLower()); + ico = XdgIcon::fromTheme(mBackend->getWindowClass(mWindow).toLower()); } if (ico.isNull()) { int devicePixels = mIconSize * devicePixelRatioF(); - ico = KX11Extras::icon(mWindow, devicePixels, devicePixels); + ico = mBackend->getApplicationIcon(mWindow, devicePixels); } setIcon(ico.isNull() ? XdgIcon::defaultApplicationIcon() : ico); } -/************************************************ - - ************************************************/ -void LXQtTaskButton::refreshIconGeometry(QRect const & geom) -{ - // NOTE: This function announces where the task icon is, - // such that X11 WMs can perform their related animations correctly. - - xcb_connection_t* x11conn = QX11Info::connection(); - - if (!x11conn) { - return; - } - - NETWinInfo info(x11conn, - windowId(), - (WId) QX11Info::appRootWindow(), - NET::WMIconGeometry, - NET::Properties2()); - NETRect const curr = info.iconGeometry(); - - // see kwindowsystem -> NETWinInfo::setIconGeometry for the scale factor - const qreal scaleFactor = qApp->devicePixelRatio(); - int xPos = geom.x() * scaleFactor; - int yPos = geom.y() * scaleFactor; - int w = geom.width() * scaleFactor; - int h = geom.height() * scaleFactor; - if (xPos == curr.pos.x && yPos == curr.pos.y && w == curr.size.width && h == curr.size.height) - return; - NETRect nrect; - nrect.pos.x = geom.x(); - nrect.pos.y = geom.y(); - nrect.size.height = geom.height(); - nrect.size.width = geom.width(); - info.setIconGeometry(nrect); -} - /************************************************ ************************************************/ @@ -223,7 +180,7 @@ void LXQtTaskButton::dragEnterEvent(QDragEnterEvent *event) event->acceptProposedAction(); if (event->mimeData()->hasFormat(mimeDataFormat())) { - emit dragging(event->source(), event->pos()); + emit dragging(event->source(), event->position().toPoint()); setAttribute(Qt::WA_UnderMouse, false); } else { @@ -237,7 +194,7 @@ void LXQtTaskButton::dragMoveEvent(QDragMoveEvent * event) { if (event->mimeData()->hasFormat(mimeDataFormat())) { - emit dragging(event->source(), event->pos()); + emit dragging(event->source(), event->position().toPoint()); setAttribute(Qt::WA_UnderMouse, false); } } @@ -253,7 +210,7 @@ void LXQtTaskButton::dropEvent(QDropEvent *event) mDNDTimer->stop(); if (event->mimeData()->hasFormat(mimeDataFormat())) { - emit dropped(event->source(), event->pos()); + emit dropped(event->source(), event->position().toPoint()); setAttribute(Qt::WA_UnderMouse, false); } QToolButton::dropEvent(event); @@ -366,7 +323,7 @@ void LXQtTaskButton::mouseMoveEvent(QMouseEvent* event) if (!(event->buttons() & Qt::LeftButton)) return; - if ((event->pos() - mDragStartPosition).manhattanLength() < QApplication::startDragDistance()) + if ((event->position().toPoint() - mDragStartPosition).manhattanLength() < QApplication::startDragDistance()) return; QDrag *drag = new QDrag(this); @@ -395,7 +352,8 @@ void LXQtTaskButton::mouseMoveEvent(QMouseEvent* event) // release mouse appropriately, by positioning the event outside // the button rectangle (otherwise, the button will be toggled) - QMouseEvent releasingEvent(QEvent::MouseButtonRelease, QPoint(-1,-1), Qt::LeftButton, Qt::NoButton, Qt::NoModifier); + //FIXME: constructor is deprecated, also seems a bit hacky code + QMouseEvent releasingEvent(QEvent::MouseButtonRelease, QPoint(-1,-1), mapToGlobal(QPoint(-1, -1)), Qt::LeftButton, Qt::NoButton, Qt::NoModifier); mouseReleaseEvent(&releasingEvent); sDraggging = false; @@ -406,8 +364,7 @@ void LXQtTaskButton::mouseMoveEvent(QMouseEvent* event) ************************************************/ bool LXQtTaskButton::isApplicationHidden() const { - KWindowInfo info(mWindow, NET::WMState); - return (info.state() & NET::Hidden); + return false; //FIXME: unused } /************************************************ @@ -415,7 +372,7 @@ bool LXQtTaskButton::isApplicationHidden() const ************************************************/ bool LXQtTaskButton::isApplicationActive() const { - return KX11Extras::activeWindow() == mWindow; + return mBackend->isWindowActive(mWindow); } /************************************************ @@ -423,21 +380,7 @@ bool LXQtTaskButton::isApplicationActive() const ************************************************/ void LXQtTaskButton::raiseApplication() { - KWindowInfo info(mWindow, NET::WMDesktop | NET::WMState | NET::XAWMState); - if (parentTaskBar()->raiseOnCurrentDesktop() && info.isMinimized()) - { - KX11Extras::setOnDesktop(mWindow, KX11Extras::currentDesktop()); - } - else - { - int winDesktop = info.desktop(); - if (KX11Extras::currentDesktop() != winDesktop) - KX11Extras::setCurrentDesktop(winDesktop); - } - // bypass focus stealing prevention - KX11Extras::forceActiveWindow(mWindow); - - setUrgencyHint(false); + mBackend->raiseWindow(mWindow, parentTaskBar()->raiseOnCurrentDesktop()); } /************************************************ @@ -445,7 +388,7 @@ void LXQtTaskButton::raiseApplication() ************************************************/ void LXQtTaskButton::minimizeApplication() { - KX11Extras::minimizeWindow(mWindow); + mBackend->setWindowState(mWindow, LXQtTaskBarWindowState::Minimized, true); } /************************************************ @@ -458,23 +401,10 @@ void LXQtTaskButton::maximizeApplication() return; int state = act->data().toInt(); - switch (state) - { - case NET::MaxHoriz: - KWindowSystem::setState(mWindow, NET::MaxHoriz); - break; - - case NET::MaxVert: - KWindowSystem::setState(mWindow, NET::MaxVert); - break; + mBackend->setWindowState(mWindow, LXQtTaskBarWindowState(state), true); - default: - KWindowSystem::setState(mWindow, NET::Max); - break; - } - - if (!isApplicationActive()) - raiseApplication(); + if(!mBackend->isWindowActive(mWindow)) + mBackend->raiseWindow(mWindow, parentTaskBar()->raiseOnCurrentDesktop()); } /************************************************ @@ -482,10 +412,10 @@ void LXQtTaskButton::maximizeApplication() ************************************************/ void LXQtTaskButton::deMaximizeApplication() { - KWindowSystem::clearState(mWindow, NET::Max); + mBackend->setWindowState(mWindow, LXQtTaskBarWindowState::Maximized, false); - if (!isApplicationActive()) - raiseApplication(); + if(!mBackend->isWindowActive(mWindow)) + mBackend->raiseWindow(mWindow, parentTaskBar()->raiseOnCurrentDesktop()); } /************************************************ @@ -493,7 +423,7 @@ void LXQtTaskButton::deMaximizeApplication() ************************************************/ void LXQtTaskButton::shadeApplication() { - KWindowSystem::setState(mWindow, NET::Shaded); + mBackend->setWindowState(mWindow, LXQtTaskBarWindowState::RolledUp, true); } /************************************************ @@ -501,7 +431,7 @@ void LXQtTaskButton::shadeApplication() ************************************************/ void LXQtTaskButton::unShadeApplication() { - KWindowSystem::clearState(mWindow, NET::Shaded); + mBackend->setWindowState(mWindow, LXQtTaskBarWindowState::RolledUp, false); } /************************************************ @@ -509,8 +439,7 @@ void LXQtTaskButton::unShadeApplication() ************************************************/ void LXQtTaskButton::closeApplication() { - // FIXME: Why there is no such thing in KWindowSystem?? - NETRootInfo(QX11Info::connection(), NET::CloseWindow).closeWindowRequest(mWindow); + mBackend->closeWindow(mWindow); } /************************************************ @@ -523,23 +452,7 @@ void LXQtTaskButton::setApplicationLayer() return; int layer = act->data().toInt(); - switch(layer) - { - case NET::KeepAbove: - KWindowSystem::clearState(mWindow, NET::KeepBelow); - KWindowSystem::setState(mWindow, NET::KeepAbove); - break; - - case NET::KeepBelow: - KWindowSystem::clearState(mWindow, NET::KeepAbove); - KWindowSystem::setState(mWindow, NET::KeepBelow); - break; - - default: - KWindowSystem::clearState(mWindow, NET::KeepBelow); - KWindowSystem::clearState(mWindow, NET::KeepAbove); - break; - } + mBackend->setWindowLayer(mWindow, LXQtTaskBarWindowLayer(layer)); } /************************************************ @@ -552,12 +465,12 @@ void LXQtTaskButton::moveApplicationToDesktop() return; bool ok; - int desk = act->data().toInt(&ok); + int idx = act->data().toInt(&ok); if (!ok) return; - KX11Extras::setOnDesktop(mWindow, desk); + mBackend->setWindowOnWorkspace(mWindow, idx); } /************************************************ @@ -565,17 +478,7 @@ void LXQtTaskButton::moveApplicationToDesktop() ************************************************/ void LXQtTaskButton::moveApplicationToPrevNextDesktop(bool next) { - int deskNum = KX11Extras::numberOfDesktops(); - if (deskNum <= 1) - return; - int targetDesk = KWindowInfo(mWindow, NET::WMDesktop).desktop() + (next ? 1 : -1); - // wrap around - if (targetDesk > deskNum) - targetDesk = 1; - else if (targetDesk < 1) - targetDesk = deskNum; - - KX11Extras::setOnDesktop(mWindow, targetDesk); + mBackend->moveApplicationToPrevNextDesktop(mWindow, next); } /************************************************ @@ -583,42 +486,7 @@ void LXQtTaskButton::moveApplicationToPrevNextDesktop(bool next) ************************************************/ void LXQtTaskButton::moveApplicationToPrevNextMonitor(bool next) { - KWindowInfo info(mWindow, NET::WMDesktop); - if (!info.isOnCurrentDesktop()) - KX11Extras::setCurrentDesktop(info.desktop()); - if (isMinimized()) - KX11Extras::unminimizeWindow(mWindow); - KX11Extras::forceActiveWindow(mWindow); - const QRect& windowGeometry = KWindowInfo(mWindow, NET::WMFrameExtents).frameGeometry(); - QList screens = QGuiApplication::screens(); - if (screens.size() > 1){ - for (int i = 0; i < screens.size(); ++i) - { - QRect screenGeometry = screens[i]->geometry(); - if (screenGeometry.intersects(windowGeometry)) - { - int targetScreen = i + (next ? 1 : -1); - if (targetScreen < 0) - targetScreen += screens.size(); - else if (targetScreen >= screens.size()) - targetScreen -= screens.size(); - QRect targetScreenGeometry = screens[targetScreen]->geometry(); - int X = windowGeometry.x() - screenGeometry.x() + targetScreenGeometry.x(); - int Y = windowGeometry.y() - screenGeometry.y() + targetScreenGeometry.y(); - NET::States state = KWindowInfo(mWindow, NET::WMState).state(); - // NW geometry | y/x | from panel - const int flags = 1 | (0b011 << 8) | (0b010 << 12); - KWindowSystem::clearState(mWindow, NET::MaxHoriz | NET::MaxVert | NET::Max | NET::FullScreen); - NETRootInfo(QX11Info::connection(), NET::Properties(), NET::WM2MoveResizeWindow).moveResizeWindowRequest(mWindow, flags, X, Y, 0, 0); - QTimer::singleShot(200, this, [this, state] - { - KWindowSystem::setState(mWindow, state); - raiseApplication(); - }); - break; - } - } - } + mBackend->moveApplicationToPrevNextMonitor(mWindow, next, parentTaskBar()->raiseOnCurrentDesktop()); } /************************************************ @@ -626,17 +494,7 @@ void LXQtTaskButton::moveApplicationToPrevNextMonitor(bool next) ************************************************/ void LXQtTaskButton::moveApplication() { - KWindowInfo info(mWindow, NET::WMDesktop); - if (!info.isOnCurrentDesktop()) - KX11Extras::setCurrentDesktop(info.desktop()); - if (isMinimized()) - KX11Extras::unminimizeWindow(mWindow); - KX11Extras::forceActiveWindow(mWindow); - const QRect& g = KWindowInfo(mWindow, NET::WMGeometry).geometry(); - int X = g.center().x(); - int Y = g.center().y(); - QCursor::setPos(X, Y); - NETRootInfo(QX11Info::connection(), NET::WMMoveResize).moveResizeRequest(mWindow, X, Y, NET::Move); + mBackend->moveApplication(mWindow); } /************************************************ @@ -644,17 +502,7 @@ void LXQtTaskButton::moveApplication() ************************************************/ void LXQtTaskButton::resizeApplication() { - KWindowInfo info(mWindow, NET::WMDesktop); - if (!info.isOnCurrentDesktop()) - KX11Extras::setCurrentDesktop(info.desktop()); - if (isMinimized()) - KX11Extras::unminimizeWindow(mWindow); - KX11Extras::forceActiveWindow(mWindow); - const QRect& g = KWindowInfo(mWindow, NET::WMGeometry).geometry(); - int X = g.bottomRight().x(); - int Y = g.bottomRight().y(); - QCursor::setPos(X, Y); - NETRootInfo(QX11Info::connection(), NET::WMMoveResize).moveResizeRequest(mWindow, X, Y, NET::BottomRight); + mBackend->resizeApplication(mWindow); } /************************************************ @@ -668,10 +516,9 @@ void LXQtTaskButton::contextMenuEvent(QContextMenuEvent* event) return; } - KWindowInfo info(mWindow, NET::Properties(), NET::WM2AllowedActions); - unsigned long state = KWindowInfo(mWindow, NET::WMState).state(); + const LXQtTaskBarWindowState state = mBackend->getWindowState(mWindow); - QMenu * menu = new QMenu(tr("Application")); + QMenu * menu = new QMenu(tr("Application"), this); menu->setAttribute(Qt::WA_DeleteOnClose); QAction* a; @@ -701,21 +548,21 @@ void LXQtTaskButton::contextMenuEvent(QContextMenuEvent* event) */ /********** Desktop menu **********/ - int deskNum = KX11Extras::numberOfDesktops(); + int deskNum = mBackend->getWorkspacesCount(); if (deskNum > 1) { - int winDesk = KWindowInfo(mWindow, NET::WMDesktop).desktop(); + int winDesk = mBackend->getWindowWorkspace(mWindow); QMenu* deskMenu = menu->addMenu(tr("To &Desktop")); a = deskMenu->addAction(tr("&All Desktops")); - a->setData(NET::OnAllDesktops); - a->setEnabled(winDesk != NET::OnAllDesktops); + a->setData(int(LXQtTaskBarWorkspace::ShowOnAll)); + a->setEnabled(winDesk != int(LXQtTaskBarWorkspace::ShowOnAll)); connect(a, &QAction::triggered, this, &LXQtTaskButton::moveApplicationToDesktop); deskMenu->addSeparator(); for (int i = 1; i <= deskNum; ++i) { - auto deskName = KX11Extras::desktopName(i).trimmed(); + auto deskName = mBackend->getWorkspaceName(i).trimmed(); if (deskName.isEmpty()) a = deskMenu->addAction(tr("Desktop &%1").arg(i)); else @@ -726,7 +573,7 @@ void LXQtTaskButton::contextMenuEvent(QContextMenuEvent* event) connect(a, &QAction::triggered, this, &LXQtTaskButton::moveApplicationToDesktop); } - int curDesk = KX11Extras::currentDesktop(); + int curDesk = mBackend->getCurrentWorkspace(); a = menu->addAction(tr("&To Current Desktop")); a->setData(curDesk); a->setEnabled(curDesk != winDesk); @@ -738,57 +585,79 @@ void LXQtTaskButton::contextMenuEvent(QContextMenuEvent* event) menu->addSeparator(); a = menu->addAction(tr("Move To N&ext Monitor")); connect(a, &QAction::triggered, this, [this] { moveApplicationToPrevNextMonitor(true); }); - a->setEnabled(info.actionSupported(NET::ActionMove) && (!(state & NET::FullScreen) || ((state & NET::FullScreen) && info.actionSupported(NET::ActionFullScreen)))); + a->setEnabled(mBackend->supportsAction(mWindow, LXQtTaskBarBackendAction::Move) && + (state != LXQtTaskBarWindowState::FullScreen + || ((state == LXQtTaskBarWindowState::FullScreen) && mBackend->supportsAction(mWindow, LXQtTaskBarBackendAction::FullScreen)))); a = menu->addAction(tr("Move To &Previous Monitor")); connect(a, &QAction::triggered, this, [this] { moveApplicationToPrevNextMonitor(false); }); } + menu->addSeparator(); a = menu->addAction(tr("&Move")); - a->setEnabled(info.actionSupported(NET::ActionMove) && !(state & NET::Max) && !(state & NET::FullScreen)); + a->setEnabled(mBackend->supportsAction(mWindow, LXQtTaskBarBackendAction::Move) + && state != LXQtTaskBarWindowState::Maximized + && state != LXQtTaskBarWindowState::FullScreen); connect(a, &QAction::triggered, this, &LXQtTaskButton::moveApplication); a = menu->addAction(tr("Resi&ze")); - a->setEnabled(info.actionSupported(NET::ActionResize) && !(state & NET::Max) && !(state & NET::FullScreen)); + a->setEnabled(mBackend->supportsAction(mWindow, LXQtTaskBarBackendAction::Resize) + && state != LXQtTaskBarWindowState::Maximized + && state != LXQtTaskBarWindowState::FullScreen); connect(a, &QAction::triggered, this, &LXQtTaskButton::resizeApplication); /********** State menu **********/ menu->addSeparator(); a = menu->addAction(tr("Ma&ximize")); - a->setEnabled(info.actionSupported(NET::ActionMax) && (!(state & NET::Max) || (state & NET::Hidden))); - a->setData(NET::Max); + a->setEnabled(mBackend->supportsAction(mWindow, LXQtTaskBarBackendAction::Maximize) + && state != LXQtTaskBarWindowState::Maximized + && state != LXQtTaskBarWindowState::Hidden); + a->setData(int(LXQtTaskBarWindowState::Maximized)); connect(a, &QAction::triggered, this, &LXQtTaskButton::maximizeApplication); if (event->modifiers() & Qt::ShiftModifier) { a = menu->addAction(tr("Maximize vertically")); - a->setEnabled(info.actionSupported(NET::ActionMaxVert) && !((state & NET::MaxVert) || (state & NET::Hidden))); - a->setData(NET::MaxVert); + a->setEnabled(mBackend->supportsAction(mWindow, LXQtTaskBarBackendAction::MaximizeVertically) + && state != LXQtTaskBarWindowState::MaximizedVertically + && state != LXQtTaskBarWindowState::Hidden); + a->setData(int(LXQtTaskBarWindowState::MaximizedVertically)); connect(a, &QAction::triggered, this, &LXQtTaskButton::maximizeApplication); a = menu->addAction(tr("Maximize horizontally")); - a->setEnabled(info.actionSupported(NET::ActionMaxHoriz) && !((state & NET::MaxHoriz) || (state & NET::Hidden))); - a->setData(NET::MaxHoriz); + a->setEnabled(mBackend->supportsAction(mWindow, LXQtTaskBarBackendAction::MaximizeHorizontally) + && state != LXQtTaskBarWindowState::MaximizedHorizontally + && state != LXQtTaskBarWindowState::Hidden); + a->setData(int(LXQtTaskBarWindowState::MaximizedHorizontally)); connect(a, &QAction::triggered, this, &LXQtTaskButton::maximizeApplication); } a = menu->addAction(tr("&Restore")); - a->setEnabled((state & NET::Hidden) || (state & NET::Max) || (state & NET::MaxHoriz) || (state & NET::MaxVert)); + a->setEnabled(state == LXQtTaskBarWindowState::Hidden + || state == LXQtTaskBarWindowState::Minimized + || state == LXQtTaskBarWindowState::Maximized + || state == LXQtTaskBarWindowState::MaximizedVertically + || state == LXQtTaskBarWindowState::MaximizedHorizontally); connect(a, &QAction::triggered, this, &LXQtTaskButton::deMaximizeApplication); a = menu->addAction(tr("Mi&nimize")); - a->setEnabled(info.actionSupported(NET::ActionMinimize) && !(state & NET::Hidden)); + a->setEnabled(mBackend->supportsAction(mWindow, LXQtTaskBarBackendAction::Minimize) + && state != LXQtTaskBarWindowState::Hidden + && state != LXQtTaskBarWindowState::Minimized); connect(a, &QAction::triggered, this, &LXQtTaskButton::minimizeApplication); - if (state & NET::Shaded) + if (state == LXQtTaskBarWindowState::RolledUp) { a = menu->addAction(tr("Roll down")); - a->setEnabled(info.actionSupported(NET::ActionShade) && !(state & NET::Hidden)); + a->setEnabled(mBackend->supportsAction(mWindow, LXQtTaskBarBackendAction::RollUp) + && state != LXQtTaskBarWindowState::Hidden + && state != LXQtTaskBarWindowState::Minimized); connect(a, &QAction::triggered, this, &LXQtTaskButton::unShadeApplication); } else { a = menu->addAction(tr("Roll up")); - a->setEnabled(info.actionSupported(NET::ActionShade) && !(state & NET::Hidden)); + a->setEnabled(mBackend->supportsAction(mWindow, LXQtTaskBarBackendAction::RollUp) + && state != LXQtTaskBarWindowState::Hidden); connect(a, &QAction::triggered, this, &LXQtTaskButton::shadeApplication); } @@ -797,22 +666,21 @@ void LXQtTaskButton::contextMenuEvent(QContextMenuEvent* event) QMenu* layerMenu = menu->addMenu(tr("&Layer")); + LXQtTaskBarWindowLayer currentLayer = mBackend->getWindowLayer(mWindow); + a = layerMenu->addAction(tr("Always on &top")); - // FIXME: There is no info.actionSupported(NET::ActionKeepAbove) - a->setEnabled(!(state & NET::KeepAbove)); - a->setData(NET::KeepAbove); + a->setEnabled(currentLayer != LXQtTaskBarWindowLayer::KeepAbove); + a->setData(int(LXQtTaskBarWindowLayer::KeepAbove)); connect(a, &QAction::triggered, this, &LXQtTaskButton::setApplicationLayer); a = layerMenu->addAction(tr("&Normal")); - a->setEnabled((state & NET::KeepAbove) || (state & NET::KeepBelow)); - // FIXME: There is no NET::KeepNormal, so passing 0 - a->setData(0); + a->setEnabled(currentLayer != LXQtTaskBarWindowLayer::Normal); + a->setData(int(LXQtTaskBarWindowLayer::Normal)); connect(a, &QAction::triggered, this, &LXQtTaskButton::setApplicationLayer); a = layerMenu->addAction(tr("Always on &bottom")); - // FIXME: There is no info.actionSupported(NET::ActionKeepBelow) - a->setEnabled(!(state & NET::KeepBelow)); - a->setData(NET::KeepBelow); + a->setEnabled(currentLayer != LXQtTaskBarWindowLayer::KeepBelow); + a->setData(int(LXQtTaskBarWindowLayer::KeepBelow)); connect(a, &QAction::triggered, this, &LXQtTaskButton::setApplicationLayer); /********** Kill menu **********/ @@ -844,17 +712,18 @@ void LXQtTaskButton::setUrgencyHint(bool set) ************************************************/ bool LXQtTaskButton::isOnDesktop(int desktop) const { - return KWindowInfo(mWindow, NET::WMDesktop).isOnDesktop(desktop); + return mBackend->getWindowWorkspace(mWindow) == desktop; } bool LXQtTaskButton::isOnCurrentScreen() const { - return QApplication::desktop()->screenGeometry(parentTaskBar()).intersects(KWindowInfo(mWindow, NET::WMFrameExtents).frameGeometry()); + QScreen *screen = parentTaskBar()->screen(); + return mBackend->isWindowOnScreen(screen, mWindow); } bool LXQtTaskButton::isMinimized() const { - return KWindowInfo(mWindow,NET::WMState | NET::XAWMState).isMinimized(); + return mBackend->getWindowState(mWindow) == LXQtTaskBarWindowState::Minimized; } Qt::Corner LXQtTaskButton::origin() const diff --git a/plugin-taskbar/lxqttaskbutton.h b/plugin-taskbar/lxqttaskbutton.h index 69f3b41d8..9ccca36fa 100644 --- a/plugin-taskbar/lxqttaskbutton.h +++ b/plugin-taskbar/lxqttaskbutton.h @@ -33,14 +33,16 @@ #include #include + #include "../panel/ilxqtpanel.h" class QPainter; class QPalette; class QMimeData; -class LXQtTaskGroup; class LXQtTaskBar; +class ILXQtTaskbarAbstractBackend; + class LeftAlignedTextStyle : public QProxyStyle { using QProxyStyle::QProxyStyle; @@ -79,7 +81,6 @@ class LXQtTaskButton : public QToolButton LXQtTaskBar * parentTaskBar() const {return mParentTaskBar;} - void refreshIconGeometry(QRect const & geom); static QString mimeDataFormat() { return QLatin1String("lxqt/lxqttaskbutton"); } /*! \return true if this button received DragEnter event (and no DragLeave event yet) * */ @@ -121,6 +122,10 @@ public slots: inline ILXQtPanelPlugin * plugin() const { return mPlugin; } +protected: + //TODO: public getter instead? + ILXQtTaskbarAbstractBackend *mBackend; + private: void moveApplicationToPrevNextDesktop(bool next); void moveApplicationToPrevNextMonitor(bool next); diff --git a/plugin-taskbar/lxqttaskgroup.cpp b/plugin-taskbar/lxqttaskgroup.cpp index b7dd7236e..c6075df89 100644 --- a/plugin-taskbar/lxqttaskgroup.cpp +++ b/plugin-taskbar/lxqttaskgroup.cpp @@ -30,6 +30,9 @@ #include "lxqttaskgroup.h" #include "lxqttaskbar.h" +#include "lxqtgrouppopup.h" + +#include "ilxqtpanelplugin.h" #include #include @@ -38,9 +41,8 @@ #include #include #include -#include -#include -#include + +#include "../panel/backends/ilxqttaskbarabstractbackend.h" /************************************************ @@ -57,14 +59,14 @@ LXQtTaskGroup::LXQtTaskGroup(const QString &groupName, WId window, LXQtTaskBar * setObjectName(groupName); setText(groupName); - connect(this, &LXQtTaskGroup::clicked, this, &LXQtTaskGroup::onClicked); - connect(KX11Extras::self(), &KX11Extras::currentDesktopChanged, this, &LXQtTaskGroup::onDesktopChanged); - connect(KX11Extras::self(), &KX11Extras::activeWindowChanged, this, &LXQtTaskGroup::onActiveWindowChanged); - connect(parent, &LXQtTaskBar::buttonRotationRefreshed, this, &LXQtTaskGroup::setAutoRotation); - connect(parent, &LXQtTaskBar::refreshIconGeometry, this, &LXQtTaskGroup::refreshIconsGeometry); - connect(parent, &LXQtTaskBar::buttonStyleRefreshed, this, &LXQtTaskGroup::setToolButtonsStyle); - connect(parent, &LXQtTaskBar::showOnlySettingChanged, this, &LXQtTaskGroup::refreshVisibility); - connect(parent, &LXQtTaskBar::popupShown, this, &LXQtTaskGroup::groupPopupShown); + connect(this, &LXQtTaskGroup::clicked, this, &LXQtTaskGroup::onClicked); + connect(parent, &LXQtTaskBar::buttonRotationRefreshed, this, &LXQtTaskGroup::setAutoRotation); + connect(parent, &LXQtTaskBar::refreshIconGeometry, this, &LXQtTaskGroup::refreshIconsGeometry); + connect(parent, &LXQtTaskBar::buttonStyleRefreshed, this, &LXQtTaskGroup::setToolButtonsStyle); + connect(parent, &LXQtTaskBar::showOnlySettingChanged, this, &LXQtTaskGroup::refreshVisibility); + connect(parent, &LXQtTaskBar::popupShown, this, &LXQtTaskGroup::groupPopupShown); + connect(mBackend, &ILXQtTaskbarAbstractBackend::currentWorkspaceChanged, this, &LXQtTaskGroup::onDesktopChanged); + connect(mBackend, &ILXQtTaskbarAbstractBackend::activeWindowChanged, this, &LXQtTaskGroup::onActiveWindowChanged); } /************************************************ @@ -96,8 +98,8 @@ void LXQtTaskGroup::contextMenuEvent(QContextMenuEvent *event) ************************************************/ void LXQtTaskGroup::closeGroup() { - for (LXQtTaskButton *button : qAsConst(mButtonHash) ) - if (button->isOnDesktop(KX11Extras::currentDesktop())) + for (LXQtTaskButton *button : std::as_const(mButtonHash) ) + if (button->isOnDesktop(mBackend->getCurrentWorkspace())) button->closeApplication(); } @@ -132,7 +134,7 @@ LXQtTaskButton * LXQtTaskGroup::addWindow(WId id) ************************************************/ LXQtTaskButton * LXQtTaskGroup::checkedButton() const { - for (LXQtTaskButton* button : qAsConst(mButtonHash)) + for (LXQtTaskButton* button : std::as_const(mButtonHash)) if (button->isChecked()) return button; @@ -191,7 +193,7 @@ LXQtTaskButton * LXQtTaskGroup::getNextPrevChildButton(bool next, bool circular) void LXQtTaskGroup::onActiveWindowChanged(WId window) { LXQtTaskButton *button = mButtonHash.value(window, nullptr); - for (LXQtTaskButton *btn : qAsConst(mButtonHash)) + for (LXQtTaskButton *btn : std::as_const(mButtonHash)) btn->setChecked(false); if (button) @@ -283,7 +285,7 @@ int LXQtTaskGroup::buttonsCount() const int LXQtTaskGroup::visibleButtonsCount() const { int i = 0; - for (LXQtTaskButton *btn : qAsConst(mButtonHash)) + for (LXQtTaskButton *btn : std::as_const(mButtonHash)) if (btn->isVisibleTo(mPopup)) i++; return i; @@ -305,7 +307,7 @@ void LXQtTaskGroup::onClicked(bool) { if (visibleButtonsCount() > 1) { - setChecked(mButtonHash.contains(KX11Extras::activeWindow())); + setChecked(mButtonHash.contains(mBackend->getActiveWindow())); setPopupVisible(true); } } @@ -323,7 +325,7 @@ void LXQtTaskGroup::regroup() mSingleButton = true; // Get first visible button LXQtTaskButton * button = nullptr; - for (LXQtTaskButton *btn : qAsConst(mButtonHash)) + for (LXQtTaskButton *btn : std::as_const(mButtonHash)) { if (btn->isVisibleTo(mPopup)) { @@ -368,7 +370,7 @@ void LXQtTaskGroup::recalculateFrameIfVisible() ************************************************/ void LXQtTaskGroup::setAutoRotation(bool value, ILXQtPanel::Position position) { - for (LXQtTaskButton *button : qAsConst(mButtonHash)) + for (LXQtTaskButton *button : std::as_const(mButtonHash)) button->setAutoRotation(false, position); LXQtTaskButton::setAutoRotation(value, position); @@ -382,9 +384,9 @@ void LXQtTaskGroup::refreshVisibility() bool will = false; LXQtTaskBar const * taskbar = parentTaskBar(); const int showDesktop = taskbar->showDesktopNum(); - for(LXQtTaskButton * btn : qAsConst(mButtonHash)) + for(LXQtTaskButton * btn : std::as_const(mButtonHash)) { - bool visible = taskbar->isShowOnlyOneDesktopTasks() ? btn->isOnDesktop(0 == showDesktop ? KX11Extras::currentDesktop() : showDesktop) : true; + bool visible = taskbar->isShowOnlyOneDesktopTasks() ? btn->isOnDesktop(0 == showDesktop ? mBackend->getCurrentWorkspace() : showDesktop) : true; visible &= taskbar->isShowOnlyCurrentScreenTasks() ? btn->isOnCurrentScreen() : true; visible &= taskbar->isShowOnlyMinimizedTasks() ? btn->isMinimized() : true; btn->setVisible(visible); @@ -444,13 +446,13 @@ void LXQtTaskGroup::refreshIconsGeometry() if (mSingleButton) { - refreshIconGeometry(rect); + mBackend->refreshIconGeometry(windowId(), rect); return; } - for(LXQtTaskButton *but : qAsConst(mButtonHash)) + for(LXQtTaskButton *but : std::as_const(mButtonHash)) { - but->refreshIconGeometry(rect); + mBackend->refreshIconGeometry(but->windowId(), rect); but->setIconSize(QSize(plugin()->panel()->iconSize(), plugin()->panel()->iconSize())); } } @@ -492,7 +494,7 @@ int LXQtTaskGroup::recalculateFrameWidth() const const QFontMetrics fm = fontMetrics(); int max = 100 * fm.horizontalAdvance(QLatin1Char(' ')); // elide after the max width int txtWidth = 0; - for (LXQtTaskButton *btn : qAsConst(mButtonHash)) + for (LXQtTaskButton *btn : std::as_const(mButtonHash)) txtWidth = qMax(fm.horizontalAdvance(btn->text()), txtWidth); return iconSize().width() + qMin(txtWidth, max) + 30/* give enough room to margins and borders*/; } @@ -538,7 +540,7 @@ void LXQtTaskGroup::leaveEvent(QEvent *event) /************************************************ ************************************************/ -void LXQtTaskGroup::enterEvent(QEvent *event) +void LXQtTaskGroup::enterEvent(QEnterEvent *event) { QToolButton::enterEvent(event); @@ -614,10 +616,12 @@ void LXQtTaskGroup::wheelEvent(QWheelEvent* event) /************************************************ ************************************************/ -bool LXQtTaskGroup::onWindowChanged(WId window, NET::Properties prop, NET::Properties2 prop2) -{ // returns true if the class is preserved +bool LXQtTaskGroup::onWindowChanged(WId window, LXQtTaskBarWindowProperty prop) +{ + // Returns true if the class is preserved + bool needsRefreshVisibility{false}; - QVector buttons; + QList buttons; if (mButtonHash.contains(window)) buttons.append(mButtonHash.value(window)); @@ -628,49 +632,47 @@ bool LXQtTaskGroup::onWindowChanged(WId window, NET::Properties prop, NET::Prope if (!buttons.isEmpty()) { // if class is changed the window won't belong to our group any more - if (parentTaskBar()->isGroupingEnabled() && prop2.testFlag(NET::WM2WindowClass)) + if (parentTaskBar()->isGroupingEnabled() && prop == LXQtTaskBarWindowProperty::WindowClass) { - KWindowInfo info(window, NET::Properties(), NET::WM2WindowClass); - if (QString::fromUtf8(info.windowClassClass()) != mGroupName) + if (mBackend->getWindowClass(windowId()) != mGroupName) { onWindowRemoved(window); return false; } } // window changed virtual desktop - if (prop.testFlag(NET::WMDesktop) || prop.testFlag(NET::WMGeometry)) + if (prop == LXQtTaskBarWindowProperty::Workspace) { if (parentTaskBar()->isShowOnlyOneDesktopTasks() - || parentTaskBar()->isShowOnlyCurrentScreenTasks()) + || parentTaskBar()->isShowOnlyCurrentScreenTasks()) { needsRefreshVisibility = true; } } - if (prop.testFlag(NET::WMVisibleName) || prop.testFlag(NET::WMName)) + if (prop == LXQtTaskBarWindowProperty::Title) std::for_each(buttons.begin(), buttons.end(), std::mem_fn(&LXQtTaskButton::updateText)); // XXX: we are setting window icon geometry -> don't need to handle NET::WMIconGeometry // Icon of the button can be based on windowClass - if (prop.testFlag(NET::WMIcon) || prop2.testFlag(NET::WM2WindowClass)) + if (prop == LXQtTaskBarWindowProperty::Icon) std::for_each(buttons.begin(), buttons.end(), std::mem_fn(&LXQtTaskButton::updateIcon)); bool set_urgency = false; bool urgency = false; - if (prop2.testFlag(NET::WM2Urgency)) + + if (prop == LXQtTaskBarWindowProperty::Urgency) { set_urgency = true; - urgency = NETWinInfo(QX11Info::connection(), window, QX11Info::appRootWindow(), NET::Properties{}, NET::WM2Urgency).urgency(); + //FIXME: original code here did not consider "demand attention", was it intentional? + urgency = mBackend->applicationDemandsAttention(window); } - if (prop.testFlag(NET::WMState)) + if (prop == LXQtTaskBarWindowProperty::State) { - KWindowInfo info{window, NET::WMState}; if (!set_urgency) - urgency = NETWinInfo(QX11Info::connection(), window, QX11Info::appRootWindow(), NET::Properties{}, NET::WM2Urgency).urgency(); - std::for_each(buttons.begin(), buttons.end(), std::bind(&LXQtTaskButton::setUrgencyHint, std::placeholders::_1, urgency || info.hasState(NET::DemandsAttention))); + urgency = mBackend->applicationDemandsAttention(window); + std::for_each(buttons.begin(), buttons.end(), std::bind(&LXQtTaskButton::setUrgencyHint, std::placeholders::_1, urgency)); set_urgency = false; - if (info.hasState(NET::SkipTaskbar)) - onWindowRemoved(window); if (parentTaskBar()->isShowOnlyMinimizedTasks()) { diff --git a/plugin-taskbar/lxqttaskgroup.h b/plugin-taskbar/lxqttaskgroup.h index 88dcccb01..31ab784fb 100644 --- a/plugin-taskbar/lxqttaskgroup.h +++ b/plugin-taskbar/lxqttaskgroup.h @@ -31,12 +31,9 @@ #ifndef LXQTTASKGROUP_H #define LXQTTASKGROUP_H -#include "../panel/ilxqtpanel.h" -#include "../panel/ilxqtpanelplugin.h" -#include "lxqttaskbar.h" -#include "lxqtgrouppopup.h" #include "lxqttaskbutton.h" -#include + +#include "../panel/backends/lxqttaskbartypes.h" class QVBoxLayout; class ILXQtPanelPlugin; @@ -63,7 +60,8 @@ class LXQtTaskGroup: public LXQtTaskButton // if circular is true, then it will go around the list of buttons LXQtTaskButton * getNextPrevChildButton(bool next, bool circular); - bool onWindowChanged(WId window, NET::Properties prop, NET::Properties2 prop2); + bool onWindowChanged(WId window, LXQtTaskBarWindowProperty prop); + void setAutoRotation(bool value, ILXQtPanel::Position position); Qt::ToolButtonStyle popupButtonStyle() const; void setToolButtonsStyle(Qt::ToolButtonStyle style); @@ -77,7 +75,7 @@ public slots: QMimeData * mimeData(); void leaveEvent(QEvent * event); - void enterEvent(QEvent * event); + void enterEvent(QEnterEvent *event); void dragEnterEvent(QDragEnterEvent * event); void dragLeaveEvent(QDragLeaveEvent * event); void contextMenuEvent(QContextMenuEvent * event); diff --git a/plugin-tray/CMakeLists.txt b/plugin-tray/CMakeLists.txt index 424b463d4..fc51b1b50 100644 --- a/plugin-tray/CMakeLists.txt +++ b/plugin-tray/CMakeLists.txt @@ -4,15 +4,15 @@ include(CheckLibraryExists) find_package(XCB REQUIRED COMPONENTS - xcb - xcb-xfixes - xcb-damage - xcb-composite - xcb-randr - xcb-shm - xcb-util - xcb-image - xcb-shape + XCB + XFIXES + DAMAGE + COMPOSITE + RANDR + SHM + UTIL + IMAGE + SHAPE ) find_package(PkgConfig) pkg_check_modules(xtst REQUIRED xtst) @@ -38,6 +38,7 @@ qt_add_dbus_adaptor(SOURCES org.kde.StatusNotifierItem.xml sniproxy.h SNIProxy) qt_add_dbus_interface(SOURCES org.kde.StatusNotifierWatcher.xml statusnotifierwatcher_interface) set(LIBRARIES + Qt6::GuiPrivate ${XCB_LIBRARIES} ${xtst_LDFLAGS} ) diff --git a/plugin-tray/fdoselectionmanager.cpp b/plugin-tray/fdoselectionmanager.cpp index 2486257c8..4afab6716 100644 --- a/plugin-tray/fdoselectionmanager.cpp +++ b/plugin-tray/fdoselectionmanager.cpp @@ -30,11 +30,12 @@ #include #include #include -#include #include #include +#include // For nativeInterface() + #include #include #include @@ -43,14 +44,26 @@ #include "sniproxy.h" #include "xcbutils.h" +//NOTE: Xlib.h defines Bool which conflicts with QJsonValue::Type enum +#include +#undef Bool +#undef Status + #define SYSTEM_TRAY_REQUEST_DOCK 0 #define SYSTEM_TRAY_BEGIN_MESSAGE 1 #define SYSTEM_TRAY_CANCEL_MESSAGE 2 FdoSelectionManager::FdoSelectionManager() - : m_atoms{new Xcb::Atoms} - , m_selectionOwner{new KSelectionOwner{m_atoms->selectionAtom, -1, this}} + : m_atoms{nullptr} + , m_selectionOwner{nullptr} { + auto *x11Application = qGuiApp->nativeInterface(); + Q_ASSERT_X(x11Application, "FdoSelectionManager", "Expected X11 connection"); + m_connection = x11Application->connection(); + + m_atoms.reset(new Xcb::Atoms(m_connection, XDefaultScreen(x11Application->display()))); + m_selectionOwner = new KSelectionOwner{m_atoms->selectionAtom, -1, this}; + qDebug() << "starting"; // we may end up calling QCoreApplication::quit() in this method, at which point we need the event loop running @@ -73,12 +86,11 @@ void FdoSelectionManager::init() qDBusRegisterMetaType(); // load damage extension - xcb_connection_t *c = QX11Info::connection(); - xcb_prefetch_extension_data(c, &xcb_damage_id); - const auto *reply = xcb_get_extension_data(c, &xcb_damage_id); + xcb_prefetch_extension_data(m_connection, &xcb_damage_id); + const auto *reply = xcb_get_extension_data(m_connection, &xcb_damage_id); if (reply && reply->present) { m_damageEventBase = reply->first_event; - xcb_damage_query_version_unchecked(c, XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MINOR_VERSION); + xcb_damage_query_version_unchecked(m_connection, XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MINOR_VERSION); } else { // no XDamage means qCritical() << "could not load damage extension. Quitting"; @@ -97,18 +109,17 @@ bool FdoSelectionManager::addDamageWatch(xcb_window_t client) { qDebug() << "adding damage watch for " << client; - xcb_connection_t *c = QX11Info::connection(); - const auto attribsCookie = xcb_get_window_attributes_unchecked(c, client); + const auto attribsCookie = xcb_get_window_attributes_unchecked(m_connection, client); - const auto damageId = xcb_generate_id(c); + const auto damageId = xcb_generate_id(m_connection); m_damageWatches[client] = damageId; - xcb_damage_create(c, damageId, client, XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY); + xcb_damage_create(m_connection, damageId, client, XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY); xcb_generic_error_t *error = nullptr; - QScopedPointer attr(xcb_get_window_attributes_reply(c, attribsCookie, &error)); - QScopedPointer getAttrError(error); + Xcb::ScopedCPointer attr(xcb_get_window_attributes_reply(m_connection, attribsCookie, &error)); + Xcb::ScopedCPointer getAttrError(error); uint32_t events = XCB_EVENT_MASK_STRUCTURE_NOTIFY; - if (!attr.isNull()) { + if (attr) { events = events | attr->your_event_mask; } // if window is already gone, there is no need to handle it. @@ -117,8 +128,8 @@ bool FdoSelectionManager::addDamageWatch(xcb_window_t client) } // the event mask will not be removed again. We cannot track whether another component also needs STRUCTURE_NOTIFY (e.g. KWindowSystem). // if we would remove the event mask again, other areas will break. - const auto changeAttrCookie = xcb_change_window_attributes_checked(c, client, XCB_CW_EVENT_MASK, &events); - QScopedPointer changeAttrError(xcb_request_check(c, changeAttrCookie)); + const auto changeAttrCookie = xcb_change_window_attributes_checked(m_connection, client, XCB_CW_EVENT_MASK, &events); + Xcb::ScopedCPointer changeAttrError(xcb_request_check(m_connection, changeAttrCookie)); // if window is gone by this point, it will be caught by eventFilter, so no need to check later errors. if (changeAttrError && changeAttrError->error_code == XCB_WINDOW) { return false; @@ -127,7 +138,7 @@ bool FdoSelectionManager::addDamageWatch(xcb_window_t client) return true; } -bool FdoSelectionManager::nativeEventFilter(const QByteArray &eventType, void *message, long int *result) +bool FdoSelectionManager::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) { Q_UNUSED(result) @@ -162,7 +173,7 @@ bool FdoSelectionManager::nativeEventFilter(const QByteArray &eventType, void *m const auto sniProxy = m_proxies.value(damagedWId); if (sniProxy) { sniProxy->update(); - xcb_damage_subtract(QX11Info::connection(), m_damageWatches[damagedWId], XCB_NONE, XCB_NONE); + xcb_damage_subtract(m_connection, m_damageWatches[damagedWId], XCB_NONE, XCB_NONE); } } else if (responseType == XCB_CONFIGURE_REQUEST) { const auto event = reinterpret_cast(ev); @@ -211,7 +222,7 @@ void FdoSelectionManager::undock(xcb_window_t winId, bool vanished) auto d_i = m_damageWatches.find(winId); if (d_i != m_damageWatches.end()) { if (!vanished) { - xcb_damage_destroy(QX11Info::connection(), *d_i); + xcb_damage_destroy(m_connection, *d_i); } m_damageWatches.erase(d_i); } @@ -239,8 +250,7 @@ void FdoSelectionManager::onLostOwnership() void FdoSelectionManager::setSystemTrayVisual() { - xcb_connection_t *c = QX11Info::connection(); - auto screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data; + auto screen = xcb_setup_roots_iterator(xcb_get_setup(m_connection)).data; auto trayVisual = screen->root_visual; xcb_depth_iterator_t depth_iterator = xcb_screen_allowed_depths_iterator(screen); xcb_depth_t *depth = nullptr; @@ -265,5 +275,5 @@ void FdoSelectionManager::setSystemTrayVisual() } } - xcb_change_property(c, XCB_PROP_MODE_REPLACE, m_selectionOwner->ownerWindow(), m_atoms->visualAtom, XCB_ATOM_VISUALID, 32, 1, &trayVisual); + xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_selectionOwner->ownerWindow(), m_atoms->visualAtom, XCB_ATOM_VISUALID, 32, 1, &trayVisual); } diff --git a/plugin-tray/fdoselectionmanager.h b/plugin-tray/fdoselectionmanager.h index b0bee5c1b..00e71e3f4 100644 --- a/plugin-tray/fdoselectionmanager.h +++ b/plugin-tray/fdoselectionmanager.h @@ -49,7 +49,7 @@ class FdoSelectionManager : public QObject, public QAbstractNativeEventFilter ~FdoSelectionManager() override; protected: - bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override; + bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override; private Q_SLOTS: void onClaimedOwnership(); @@ -65,6 +65,7 @@ private Q_SLOTS: uint8_t m_damageEventBase; + xcb_connection_t *m_connection; QHash m_damageWatches; QHash m_proxies; std::unique_ptr m_atoms; diff --git a/plugin-tray/lxqttrayplugin.cpp b/plugin-tray/lxqttrayplugin.cpp index 3c906fd8d..a21c72e2e 100644 --- a/plugin-tray/lxqttrayplugin.cpp +++ b/plugin-tray/lxqttrayplugin.cpp @@ -29,6 +29,8 @@ #include "lxqttrayplugin.h" #include "fdoselectionmanager.h" +#include // For nativeInterface() + LXQtTrayPlugin::LXQtTrayPlugin(const ILXQtPanelPluginStartupInfo &startupInfo) : QObject() , ILXQtPanelPlugin(startupInfo) @@ -44,3 +46,16 @@ QWidget *LXQtTrayPlugin::widget() { return nullptr; } + +ILXQtPanelPlugin *LXQtTrayPluginLibrary::instance(const ILXQtPanelPluginStartupInfo &startupInfo) const +{ + auto *x11Application = qGuiApp->nativeInterface(); + if(!x11Application || !x11Application->connection()) + { + // Currently only X11 supported + qWarning() << "Currently tray plugin supports X11 only. Skipping."; + return nullptr; + } + + return new LXQtTrayPlugin(startupInfo); +} diff --git a/plugin-tray/lxqttrayplugin.h b/plugin-tray/lxqttrayplugin.h index e8ddd78c0..3bdc6948f 100644 --- a/plugin-tray/lxqttrayplugin.h +++ b/plugin-tray/lxqttrayplugin.h @@ -29,9 +29,10 @@ #pragma once #include "../panel/ilxqtpanelplugin.h" -#include + #include -#include + +#include class FdoSelectionManager; class LXQtTrayPlugin : public QObject, public ILXQtPanelPlugin @@ -58,13 +59,5 @@ class LXQtTrayPluginLibrary: public QObject, public ILXQtPanelPluginLibrary // Q_PLUGIN_METADATA(IID "lxqt.org/Panel/PluginInterface/3.0") Q_INTERFACES(ILXQtPanelPluginLibrary) public: - ILXQtPanelPlugin *instance(const ILXQtPanelPluginStartupInfo &startupInfo) const - { - // Currently only X11 supported - if (!QX11Info::connection()) { - qWarning() << "Currently tray plugin supports X11 only. Skipping."; - return nullptr; - } - return new LXQtTrayPlugin(startupInfo); - } + ILXQtPanelPlugin *instance(const ILXQtPanelPluginStartupInfo &startupInfo) const; }; diff --git a/plugin-tray/snidbus.h b/plugin-tray/snidbus.h index f05a7465d..2ee79821d 100644 --- a/plugin-tray/snidbus.h +++ b/plugin-tray/snidbus.h @@ -30,7 +30,7 @@ #include #include #include -#include +#include // Custom message type for DBus struct KDbusImageStruct { @@ -41,7 +41,7 @@ struct KDbusImageStruct { QByteArray data; }; -typedef QVector KDbusImageVector; +typedef QList KDbusImageVector; struct KDbusToolTipStruct { QString icon; diff --git a/plugin-tray/sniproxy.cpp b/plugin-tray/sniproxy.cpp index a0c732147..4cb05ce97 100644 --- a/plugin-tray/sniproxy.cpp +++ b/plugin-tray/sniproxy.cpp @@ -28,27 +28,35 @@ #include "sniproxy.h" #include -#include -#include - -#include "xcbutils.h" #include #include #include #include -#include #include #include #include +#include //For "gettimestamp" Xcb integration resource +#include "kwindowinfo.h" #include "statusnotifieritemadaptor.h" #include "statusnotifierwatcher_interface.h" #include "xtestsender.h" + +#include +#include + +#include "xcbutils.h" + +//NOTE: Xlib.h defines Bool which conflicts with QJsonValue::Type enum +#include +#undef Bool +#undef Status + //#define VISUAL_DEBUG #define SNI_WATCHER_SERVICE_NAME "org.kde.StatusNotifierWatcher" @@ -59,7 +67,7 @@ static unsigned int XEMBED_VERSION = 0; int SNIProxy::s_serviceCount = 0; -void xembed_message_send(Xcb::Atoms & atoms, xcb_window_t towin, long message, long d1, long d2, long d3) +void xembed_message_send(xcb_connection_t *conn, Xcb::Atoms & atoms, xcb_window_t towin, long message, long d1, long d2, long d3) { xcb_client_message_event_t ev; @@ -72,7 +80,7 @@ void xembed_message_send(Xcb::Atoms & atoms, xcb_window_t towin, long message, l ev.data.data32[3] = d2; ev.data.data32[4] = d3; ev.type = atoms.xembedAtom; - xcb_send_event(QX11Info::connection(), false, towin, XCB_EVENT_MASK_NO_EVENT, (char *)&ev); + xcb_send_event(conn, false, towin, XCB_EVENT_MASK_NO_EVENT, (char *)&ev); } static QRect findOpaqueArea(const QImage & image, int margin = 0) @@ -103,11 +111,16 @@ SNIProxy::SNIProxy(xcb_window_t wid, Xcb::Atoms & atoms, QObject *parent) // there is an undocumented feature that you can register an SNI by path, however it doesn't detect an object on a service being removed, only the entire // service closing instead lets use one DBus connection per SNI m_dbus(QDBusConnection::connectToBus(QDBusConnection::SessionBus, QStringLiteral("XembedSniProxy%1").arg(s_serviceCount++))) + , m_connection(nullptr) , m_windowId(wid) , sendingClickEvent(false) , m_injectMode(Direct) , m_atoms{atoms} { + auto *x11Application = qGuiApp->nativeInterface(); + Q_ASSERT_X(x11Application, "SNIProxy", "Expected X11 connection"); + m_connection = x11Application->connection(); + resizeWindow(s_embedSize, s_embedSize); // create new SNI @@ -122,11 +135,9 @@ SNIProxy::SNIProxy(xcb_window_t wid, Xcb::Atoms & atoms, QObject *parent) qWarning() << "could not register SNI:" << reply.error().message(); } - auto c = QX11Info::connection(); - // create a container window - auto screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data; - m_containerWid = xcb_generate_id(c); + auto screen = xcb_setup_roots_iterator(xcb_get_setup(m_connection)).data; + m_containerWid = xcb_generate_id(m_connection); uint32_t values[3]; uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; values[0] = screen->black_pixel; // draw a solid background so the embedded icon doesn't get garbage in it @@ -134,7 +145,7 @@ SNIProxy::SNIProxy(xcb_window_t wid, Xcb::Atoms & atoms, QObject *parent) values[2] = XCB_EVENT_MASK_VISIBILITY_CHANGE | // receive visibility change, to handle KWin restart #357443 // Redirect and handle structure (size, position) requests from the embedded window. XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; - xcb_create_window(c, /* connection */ + xcb_create_window(m_connection, /* connection */ XCB_COPY_FROM_PARENT, /* depth */ m_containerWid, /* window Id */ screen->root, /* parent window */ @@ -163,42 +174,42 @@ SNIProxy::SNIProxy(xcb_window_t wid, Xcb::Atoms & atoms, QObject *parent) #ifndef VISUAL_DEBUG stackContainerWindow(XCB_STACK_MODE_BELOW); - NETWinInfo wm(c, m_containerWid, screen->root, NET::Properties(), NET::Properties2()); + NETWinInfo wm(m_connection, m_containerWid, screen->root, NET::Properties(), NET::Properties2()); wm.setOpacity(0); #endif - xcb_flush(c); + xcb_flush(m_connection); - xcb_map_window(c, m_containerWid); + xcb_map_window(m_connection, m_containerWid); - xcb_reparent_window(c, m_windowId, m_containerWid, 0, 0); + xcb_reparent_window(m_connection, m_windowId, m_containerWid, 0, 0); /* * Render the embedded window offscreen */ - xcb_composite_redirect_window(c, m_windowId, XCB_COMPOSITE_REDIRECT_MANUAL); + xcb_composite_redirect_window(m_connection, m_windowId, XCB_COMPOSITE_REDIRECT_MANUAL); /* we grab the window, but also make sure it's automatically reparented back * to the root window if we should die. */ - xcb_change_save_set(c, XCB_SET_MODE_INSERT, m_windowId); + xcb_change_save_set(m_connection, XCB_SET_MODE_INSERT, m_windowId); // tell client we're embedding it - xembed_message_send(m_atoms, m_windowId, XEMBED_EMBEDDED_NOTIFY, 0, m_containerWid, XEMBED_VERSION); + xembed_message_send(m_connection, m_atoms, m_windowId, XEMBED_EMBEDDED_NOTIFY, 0, m_containerWid, XEMBED_VERSION); // move window we're embedding const uint32_t windowMoveConfigVals[2] = {0, 0}; - xcb_configure_window(c, m_windowId, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, windowMoveConfigVals); + xcb_configure_window(m_connection, m_windowId, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, windowMoveConfigVals); QSize clientWindowSize = calculateClientWindowSize(); // show the embedded window otherwise nothing happens - xcb_map_window(c, m_windowId); + xcb_map_window(m_connection, m_windowId); - xcb_clear_area(c, 0, m_windowId, 0, 0, clientWindowSize.width(), clientWindowSize.height()); + xcb_clear_area(m_connection, 0, m_windowId, 0, 0, clientWindowSize.width(), clientWindowSize.height()); - xcb_flush(c); + xcb_flush(m_connection); // guess which input injection method to use // we can either send an X event to the client or XTest @@ -207,8 +218,8 @@ SNIProxy::SNIProxy(xcb_window_t wid, Xcb::Atoms & atoms, QObject *parent) // we query if the client selected button presses in the event mask // if the client does supports that we send directly, otherwise we'll use xtest - auto waCookie = xcb_get_window_attributes(c, m_windowId); - QScopedPointer windowAttributes(xcb_get_window_attributes_reply(c, waCookie, nullptr)); + auto waCookie = xcb_get_window_attributes(m_connection, m_windowId); + Xcb::ScopedCPointer windowAttributes(xcb_get_window_attributes_reply(m_connection, waCookie, nullptr)); if (windowAttributes && !(windowAttributes->all_event_masks & XCB_EVENT_MASK_BUTTON_PRESS)) { m_injectMode = XTest; } @@ -221,12 +232,15 @@ SNIProxy::SNIProxy(xcb_window_t wid, Xcb::Atoms & atoms, QObject *parent) SNIProxy::~SNIProxy() { - auto c = QX11Info::connection(); + auto *x11Application = qGuiApp->nativeInterface(); + Q_ASSERT_X(x11Application, "SNIProxy", "Expected X11 connection"); + + WId appRootWindow = XDefaultRootWindow(x11Application->display()); if (!m_vanished) { - xcb_reparent_window(c, m_windowId, QX11Info::appRootWindow(), 0, 0); + xcb_reparent_window(m_connection, m_windowId, appRootWindow, 0, 0); } - xcb_destroy_window(c, m_containerWid); + xcb_destroy_window(m_connection, m_containerWid); QDBusConnection::disconnectFromBus(m_dbus.name()); } @@ -246,12 +260,10 @@ void SNIProxy::update() void SNIProxy::resizeWindow(const uint16_t width, const uint16_t height) const { - auto connection = QX11Info::connection(); - const uint32_t windowSizeConfigVals[2] = {width, height}; - xcb_configure_window(connection, m_windowId, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, windowSizeConfigVals); + xcb_configure_window(m_connection, m_windowId, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, windowSizeConfigVals); - xcb_flush(connection); + xcb_flush(m_connection); } void SNIProxy::hideContainerWindow(xcb_window_t windowId) const @@ -264,10 +276,8 @@ void SNIProxy::hideContainerWindow(xcb_window_t windowId) const QSize SNIProxy::calculateClientWindowSize() const { - auto c = QX11Info::connection(); - - auto cookie = xcb_get_geometry(c, m_windowId); - QScopedPointer clientGeom(xcb_get_geometry_reply(c, cookie, nullptr)); + auto cookie = xcb_get_geometry(m_connection, m_windowId); + Xcb::ScopedCPointer clientGeom(xcb_get_geometry_reply(m_connection, cookie, nullptr)); QSize clientWindowSize; if (clientGeom) { @@ -318,11 +328,9 @@ bool SNIProxy::isTransparentImage(const QImage &image) const QImage SNIProxy::getImageNonComposite() const { - auto c = QX11Info::connection(); - QSize clientWindowSize = calculateClientWindowSize(); - xcb_image_t *image = xcb_image_get(c, m_windowId, 0, 0, clientWindowSize.width(), clientWindowSize.height(), 0xFFFFFFFF, XCB_IMAGE_FORMAT_Z_PIXMAP); + xcb_image_t *image = xcb_image_get(m_connection, m_windowId, 0, 0, clientWindowSize.width(), clientWindowSize.height(), 0xFFFFFFFF, XCB_IMAGE_FORMAT_Z_PIXMAP); // Don't hook up cleanup yet, we may use a different QImage after all QImage naiveConversion; @@ -393,7 +401,7 @@ QImage SNIProxy::convertFromNative(xcb_image_t *xcbImage) const if (format == QImage::Format_RGB32 && xcbImage->bpp == 32) { QImage m = image.createHeuristicMask(); - QBitmap mask(QPixmap::fromImage(m)); + QBitmap mask = QBitmap::fromImage(m); QPixmap p = QPixmap::fromImage(image); p.setMask(mask); image = p.toImage(); @@ -417,15 +425,13 @@ QPoint SNIProxy::calculateClickPoint() const { QPoint clickPoint = QPoint(0, 0); - auto c = QX11Info::connection(); - // request extent to check if shape has been set - xcb_shape_query_extents_cookie_t extentsCookie = xcb_shape_query_extents(c, m_windowId); + xcb_shape_query_extents_cookie_t extentsCookie = xcb_shape_query_extents(m_connection, m_windowId); // at the same time make the request for rectangles (even if this request isn't needed) - xcb_shape_get_rectangles_cookie_t rectaglesCookie = xcb_shape_get_rectangles(c, m_windowId, XCB_SHAPE_SK_BOUNDING); + xcb_shape_get_rectangles_cookie_t rectaglesCookie = xcb_shape_get_rectangles(m_connection, m_windowId, XCB_SHAPE_SK_BOUNDING); - QScopedPointer extentsReply(xcb_shape_query_extents_reply(c, extentsCookie, nullptr)); - QScopedPointer rectanglesReply(xcb_shape_get_rectangles_reply(c, rectaglesCookie, nullptr)); + Xcb::ScopedCPointer extentsReply(xcb_shape_query_extents_reply(m_connection, extentsCookie, nullptr)); + Xcb::ScopedCPointer rectanglesReply(xcb_shape_get_rectangles_reply(m_connection, rectaglesCookie, nullptr)); if (!extentsReply || !rectanglesReply || !extentsReply->bounding_shaped) { return clickPoint; @@ -452,9 +458,8 @@ QPoint SNIProxy::calculateClickPoint() const void SNIProxy::stackContainerWindow(const uint32_t stackMode) const { - auto c = QX11Info::connection(); const uint32_t stackData[] = {stackMode}; - xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackData); + xcb_configure_window(m_connection, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackData); } //____________properties__________ @@ -548,17 +553,15 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) qDebug() << "Received click" << mouseButton << "with passed x*y" << x << y; sendingClickEvent = true; - auto c = QX11Info::connection(); - - auto cookieSize = xcb_get_geometry(c, m_windowId); - QScopedPointer clientGeom(xcb_get_geometry_reply(c, cookieSize, nullptr)); + auto cookieSize = xcb_get_geometry(m_connection, m_windowId); + Xcb::ScopedCPointer clientGeom(xcb_get_geometry_reply(m_connection, cookieSize, nullptr)); if (!clientGeom) { return; } - auto cookie = xcb_query_pointer(c, m_windowId); - QScopedPointer pointer(xcb_query_pointer_reply(c, cookie, nullptr)); + auto cookie = xcb_query_pointer(m_connection, m_windowId); + Xcb::ScopedCPointer pointer(xcb_query_pointer_reply(m_connection, cookie, nullptr)); /*qDebug() << "samescreen" << pointer->same_screen << endl << "root x*y" << pointer->root_x << pointer->root_y << endl << "win x*y" << pointer->win_x << pointer->win_y;*/ @@ -580,20 +583,27 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) else configVals[1] = static_cast(y - clickPoint.y()); } - xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, configVals); + xcb_configure_window(m_connection, m_containerWid, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, configVals); // pull window up stackContainerWindow(XCB_STACK_MODE_ABOVE); + auto *x11Application = qGuiApp->nativeInterface(); + WId appRootWindow = XDefaultRootWindow(x11Application->display()); + + // Qt private access + void *ptr = qGuiApp->platformNativeInterface()->nativeResourceForScreen("gettimestamp", qGuiApp->primaryScreen()); + xcb_timestamp_t timeStamp = reinterpret_cast(ptr); + // mouse down if (m_injectMode == Direct) { xcb_button_press_event_t *event = new xcb_button_press_event_t; memset(event, 0x00, sizeof(xcb_button_press_event_t)); event->response_type = XCB_BUTTON_PRESS; event->event = m_windowId; - event->time = QX11Info::getTimestamp(); + event->time = timeStamp; event->same_screen = 1; - event->root = QX11Info::appRootWindow(); + event->root = appRootWindow; event->root_x = x; event->root_y = y; event->event_x = static_cast(clickPoint.x()); @@ -602,10 +612,10 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) event->state = 0; event->detail = mouseButton; - xcb_send_event(c, false, m_windowId, XCB_EVENT_MASK_BUTTON_PRESS, (char *)event); + xcb_send_event(m_connection, false, m_windowId, XCB_EVENT_MASK_BUTTON_PRESS, (char *)event); delete event; } else { - sendXTestPressed(QX11Info::display(), mouseButton); + sendXTestPressed(x11Application->display(), mouseButton); } // mouse up @@ -614,9 +624,9 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) memset(event, 0x00, sizeof(xcb_button_release_event_t)); event->response_type = XCB_BUTTON_RELEASE; event->event = m_windowId; - event->time = QX11Info::getTimestamp(); + event->time = timeStamp; event->same_screen = 1; - event->root = QX11Info::appRootWindow(); + event->root = appRootWindow; event->root_x = x; event->root_y = y; event->event_x = static_cast(clickPoint.x()); @@ -625,10 +635,10 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) event->state = 0; event->detail = mouseButton; - xcb_send_event(c, false, m_windowId, XCB_EVENT_MASK_BUTTON_RELEASE, (char *)event); + xcb_send_event(m_connection, false, m_windowId, XCB_EVENT_MASK_BUTTON_RELEASE, (char *)event); delete event; } else { - sendXTestReleased(QX11Info::display(), mouseButton); + sendXTestReleased(x11Application->display(), mouseButton); } #ifndef VISUAL_DEBUG diff --git a/plugin-tray/sniproxy.h b/plugin-tray/sniproxy.h index f31b46597..8587568c3 100644 --- a/plugin-tray/sniproxy.h +++ b/plugin-tray/sniproxy.h @@ -168,6 +168,7 @@ public Q_SLOTS: void stackContainerWindow(const uint32_t stackMode) const; QDBusConnection m_dbus; + xcb_connection_t *m_connection; xcb_window_t m_windowId; xcb_window_t m_containerWid; static int s_serviceCount; diff --git a/plugin-tray/xcbutils.h b/plugin-tray/xcbutils.h index 6711b259d..497aa8c84 100644 --- a/plugin-tray/xcbutils.h +++ b/plugin-tray/xcbutils.h @@ -35,9 +35,8 @@ #include #include -#include -#include -#include +#include +#include /** XEMBED messages */ #define XEMBED_EMBEDDED_NOTIFY 0 @@ -53,13 +52,19 @@ namespace Xcb { typedef xcb_window_t WindowId; +struct ScopedCPointerDeleter +{ + static inline void cleanup(void *pointer) noexcept { free(pointer); } + void operator()(void *pointer) const noexcept { cleanup(pointer); } +}; + template -using ScopedCPointer = QScopedPointer; +using ScopedCPointer = std::unique_ptr; class Atom { public: - explicit Atom(const QByteArray &name, bool onlyIfExists = false, xcb_connection_t *c = QX11Info::connection()) + explicit Atom(const QByteArray &name, xcb_connection_t *c, bool onlyIfExists = false) : m_connection(c) , m_retrieved(false) , m_cookie(xcb_intern_atom_unchecked(m_connection, onlyIfExists, name.length(), name.constData())) @@ -105,7 +110,7 @@ class Atom return; } ScopedCPointer reply(xcb_intern_atom_reply(m_connection, m_cookie, nullptr)); - if (!reply.isNull()) { + if (reply) { m_atom = reply->atom; } m_retrieved = true; @@ -120,12 +125,12 @@ class Atom class Atoms { public: - Atoms() - : xembedAtom("_XEMBED") - , selectionAtom(xcb_atom_name_by_screen("_NET_SYSTEM_TRAY", QX11Info::appScreen())) - , opcodeAtom("_NET_SYSTEM_TRAY_OPCODE") - , messageData("_NET_SYSTEM_TRAY_MESSAGE_DATA") - , visualAtom("_NET_SYSTEM_TRAY_VISUAL") + Atoms(xcb_connection_t *c, int defaultScreen) + : xembedAtom("_XEMBED", c) + , selectionAtom(xcb_atom_name_by_screen("_NET_SYSTEM_TRAY", defaultScreen), c) + , opcodeAtom("_NET_SYSTEM_TRAY_OPCODE", c) + , messageData("_NET_SYSTEM_TRAY_MESSAGE_DATA", c) + , visualAtom("_NET_SYSTEM_TRAY_VISUAL", c) { } diff --git a/plugin-volume/CMakeLists.txt b/plugin-volume/CMakeLists.txt index 55457b17f..8527a18e2 100644 --- a/plugin-volume/CMakeLists.txt +++ b/plugin-volume/CMakeLists.txt @@ -27,7 +27,7 @@ set(UIS set(LIBRARIES ${LIBRARIES} lxqt-globalkeys - Qt5Xdg + Qt6Xdg ) if(PULSEAUDIO_FOUND) diff --git a/plugin-volume/alsaengine.cpp b/plugin-volume/alsaengine.cpp index a0bdff521..1d0786b09 100644 --- a/plugin-volume/alsaengine.cpp +++ b/plugin-volume/alsaengine.cpp @@ -70,7 +70,7 @@ int AlsaEngine::volumeMax(AudioDevice *device) const AlsaDevice *AlsaEngine::getDeviceByAlsaElem(snd_mixer_elem_t *elem) const { - for (AudioDevice *device : qAsConst(m_sinks)) { + for (AudioDevice *device : std::as_const(m_sinks)) { AlsaDevice *dev = qobject_cast(device); if (!dev || !dev->element()) continue; diff --git a/plugin-volume/lxqtvolumeconfiguration.cpp b/plugin-volume/lxqtvolumeconfiguration.cpp index beb61cd62..5075c37a4 100644 --- a/plugin-volume/lxqtvolumeconfiguration.cpp +++ b/plugin-volume/lxqtvolumeconfiguration.cpp @@ -80,7 +80,7 @@ void LXQtVolumeConfiguration::setSinkList(const QList sinks) const bool old_block = ui->devAddedCombo->blockSignals(true); ui->devAddedCombo->clear(); - for (const AudioDevice *dev : qAsConst(sinks)) { + for (const AudioDevice *dev : std::as_const(sinks)) { ui->devAddedCombo->addItem(dev->description(), dev->index()); } diff --git a/plugin-volume/pulseaudioengine.cpp b/plugin-volume/pulseaudioengine.cpp index 9b48ed828..041aae0af 100644 --- a/plugin-volume/pulseaudioengine.cpp +++ b/plugin-volume/pulseaudioengine.cpp @@ -179,8 +179,8 @@ void PulseAudioEngine::removeSink(uint32_t idx) if (m_sinks.end() == dev_i) return; - QScopedPointer dev{*dev_i}; - m_cVolumeMap.remove(dev.data()); + std::unique_ptr dev{*dev_i}; + m_cVolumeMap.remove(dev.get()); m_sinks.erase(dev_i); emit sinkListChanged(); } @@ -191,7 +191,7 @@ void PulseAudioEngine::addOrUpdateSink(const pa_sink_info *info) bool newSink = false; QString name = QString::fromUtf8(info->name); - for (AudioDevice *device : qAsConst(m_sinks)) { + for (AudioDevice *device : std::as_const(m_sinks)) { if (device->name() == name) { dev = device; break; diff --git a/plugin-volume/volumebutton.cpp b/plugin-volume/volumebutton.cpp index 95df40460..f10e2d0b6 100644 --- a/plugin-volume/volumebutton.cpp +++ b/plugin-volume/volumebutton.cpp @@ -77,10 +77,10 @@ void VolumeButton::setMixerCommand(const QString &command) m_mixerCommand = m_mixerParams.empty() ? QString{} : m_mixerParams.takeFirst(); } -void VolumeButton::enterEvent(QEvent *event) +void VolumeButton::enterEvent(QEnterEvent *event) { // show tooltip immediately on entering widget - QToolTip::showText(static_cast(event)->globalPos(), toolTip(), this); + QToolTip::showText(event->globalPosition().toPoint(), toolTip(), this); } void VolumeButton::mouseMoveEvent(QMouseEvent *event) @@ -88,7 +88,7 @@ void VolumeButton::mouseMoveEvent(QMouseEvent *event) QToolButton::mouseMoveEvent(event); // show tooltip immediately on moving the mouse if (!QToolTip::isVisible()) // prevent sliding of tooltip - QToolTip::showText(event->globalPos(), toolTip(), this); + QToolTip::showText(event->globalPosition().toPoint(), toolTip(), this); } void VolumeButton::wheelEvent(QWheelEvent *event) diff --git a/plugin-volume/volumebutton.h b/plugin-volume/volumebutton.h index aabbd5b76..a113a5dac 100644 --- a/plugin-volume/volumebutton.h +++ b/plugin-volume/volumebutton.h @@ -51,7 +51,7 @@ public slots: void showVolumeSlider(); protected: - void enterEvent(QEvent *event) override; + void enterEvent(QEnterEvent *event) override; void wheelEvent(QWheelEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; diff --git a/plugin-volume/volumepopup.cpp b/plugin-volume/volumepopup.cpp index 24a50afae..5b589a8c1 100644 --- a/plugin-volume/volumepopup.cpp +++ b/plugin-volume/volumepopup.cpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include "audioengine.h" #include @@ -75,7 +74,7 @@ VolumePopup::VolumePopup(QWidget* parent): QVBoxLayout *l = new QVBoxLayout(this); l->setSpacing(0); - l->setMargin(0); + l->setContentsMargins(QMargins()); l->addWidget(m_mixerButton, 0, Qt::AlignHCenter); l->addWidget(m_volumeSlider, 0, Qt::AlignHCenter); @@ -110,7 +109,7 @@ bool VolumePopup::eventFilter(QObject * watched, QEvent * event) return QDialog::eventFilter(watched, event); } -void VolumePopup::enterEvent(QEvent * /*event*/) +void VolumePopup::enterEvent(QEnterEvent * /*event*/) { emit mouseEntered(); } diff --git a/plugin-volume/volumepopup.h b/plugin-volume/volumepopup.h index 8d98be0ad..63facdc67 100644 --- a/plugin-volume/volumepopup.h +++ b/plugin-volume/volumepopup.h @@ -60,7 +60,7 @@ class VolumePopup : public QDialog protected: void resizeEvent(QResizeEvent *event) override; - void enterEvent(QEvent *event) override; + void enterEvent(QEnterEvent *event) override; void leaveEvent(QEvent *event) override; bool event(QEvent * event) override; bool eventFilter(QObject * watched, QEvent * event) override; diff --git a/plugin-worldclock/lxqtworldclock.cpp b/plugin-worldclock/lxqtworldclock.cpp index f9ef5e1c6..b5557bdd2 100644 --- a/plugin-worldclock/lxqtworldclock.cpp +++ b/plugin-worldclock/lxqtworldclock.cpp @@ -32,7 +32,6 @@ #include #include -#include #include #include #include @@ -165,6 +164,8 @@ void LXQtWorldClock::restartTimer() void LXQtWorldClock::settingsChanged() { + static QRegularExpression regexp(QLatin1String("'[^']*'")); + PluginSettings *_settings = settings(); QString oldFormat = mFormat; @@ -324,7 +325,7 @@ void LXQtWorldClock::settingsChanged() { int update_interval; QString format = mFormat; - format.replace(QRegExp(QLatin1String("'[^']*'")), QString()); + format.replace(regexp, QString()); //don't support updating on millisecond basis -> big performance hit if (format.contains(QLatin1String("s"))) update_interval = 1000; @@ -457,7 +458,7 @@ void LXQtWorldClock::updatePopupContent() QStringList allTimeZones; bool hasTimeZone = formatHasTimeZone(mFormat); - for (QString timeZoneName : qAsConst(mTimeZones)) + for (QString timeZoneName : std::as_const(mTimeZones)) { if (timeZoneName == QLatin1String("local")) timeZoneName = QString::fromLatin1(QTimeZone::systemTimeZoneId()); @@ -476,7 +477,8 @@ void LXQtWorldClock::updatePopupContent() bool LXQtWorldClock::formatHasTimeZone(QString format) { - format.replace(QRegExp(QLatin1String("'[^']*'")), QString()); + static QRegularExpression regexp(QLatin1String("'[^']*'")); + format.replace(regexp, QString()); return format.contains(QLatin1Char('t'), Qt::CaseInsensitive); } @@ -622,7 +624,7 @@ LXQtWorldClockPopup::LXQtWorldClockPopup(QWidget *parent) : QDialog(parent, Qt::Window | Qt::WindowStaysOnTopHint | Qt::CustomizeWindowHint | Qt::Popup | Qt::X11BypassWindowManagerHint) { setLayout(new QHBoxLayout(this)); - layout()->setMargin(1); + layout()->setContentsMargins(1, 1, 1, 1); } void LXQtWorldClockPopup::show() diff --git a/plugin-worldclock/lxqtworldclockconfiguration.cpp b/plugin-worldclock/lxqtworldclockconfiguration.cpp index 384abc260..1dd2f59f3 100644 --- a/plugin-worldclock/lxqtworldclockconfiguration.cpp +++ b/plugin-worldclock/lxqtworldclockconfiguration.cpp @@ -494,7 +494,7 @@ void LXQtWorldClockConfiguration::updateTimeZoneButtons() int LXQtWorldClockConfiguration::findTimeZone(const QString& timeZone) { QList items = ui->timeZonesTW->findItems(timeZone, Qt::MatchExactly); - for (const QTableWidgetItem* item : qAsConst(items)) + for (const QTableWidgetItem* item : std::as_const(items)) if (item->column() == 0) return item->row(); return -1; diff --git a/plugin-worldclock/lxqtworldclockconfigurationtimezones.cpp b/plugin-worldclock/lxqtworldclockconfigurationtimezones.cpp index 2cb3d93b6..3e1630735 100644 --- a/plugin-worldclock/lxqtworldclockconfigurationtimezones.cpp +++ b/plugin-worldclock/lxqtworldclockconfigurationtimezones.cpp @@ -119,7 +119,7 @@ int LXQtWorldClockConfigurationTimeZones::updateAndExec() if (qStrings.size() == 1) qStrings.prepend(tr("Other")); - QTreeWidgetItem *tzItem = new QTreeWidgetItem(QStringList() << qStrings[qStrings.length() - 1] << timeZone.displayName(now) << timeZone.comment() << QLocale::countryToString(timeZone.country())); + QTreeWidgetItem *tzItem = new QTreeWidgetItem(QStringList() << qStrings[qStrings.length() - 1] << timeZone.displayName(now) << timeZone.comment() << QLocale::territoryToString(timeZone.territory())); tzItem->setData(0, Qt::UserRole, ianaId); makeSureParentsExist(qStrings, parentItems)->addChild(tzItem);