From 5dc5d82cdef3b89137d44611b0adb73a7e4750b6 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 11 Feb 2024 12:53:06 +0100 Subject: [PATCH 01/92] CMake: FindXCB components are upper case Fixes CMake error --- plugin-kbindicator/CMakeLists.txt | 2 +- plugin-tray/CMakeLists.txt | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plugin-kbindicator/CMakeLists.txt b/plugin-kbindicator/CMakeLists.txt index 29a208f9d..ab1d45d53 100644 --- a/plugin-kbindicator/CMakeLists.txt +++ b/plugin-kbindicator/CMakeLists.txt @@ -29,7 +29,7 @@ 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) diff --git a/plugin-tray/CMakeLists.txt b/plugin-tray/CMakeLists.txt index 424b463d4..a0541e226 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) From 07f702a3e09c290895a066ed7cf1b182a64a6972 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 00:50:40 +0100 Subject: [PATCH 02/92] CMake: update dependencies for Qt6 --- CMakeLists.txt | 21 ++++++++++----------- cmake/BuildPlugin.cmake | 8 ++++---- panel/CMakeLists.txt | 4 ++-- plugin-customcommand/CMakeLists.txt | 2 +- plugin-directorymenu/CMakeLists.txt | 2 +- plugin-kbindicator/CMakeLists.txt | 4 ++-- plugin-mount/CMakeLists.txt | 4 ++-- plugin-quicklaunch/CMakeLists.txt | 2 +- plugin-showdesktop/CMakeLists.txt | 2 +- plugin-statusnotifier/CMakeLists.txt | 10 +++++----- plugin-sysstat/CMakeLists.txt | 4 ++-- plugin-taskbar/CMakeLists.txt | 2 +- plugin-volume/CMakeLists.txt | 2 +- 13 files changed, 33 insertions(+), 34 deletions(-) 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/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..916fced2c 100644 --- a/panel/CMakeLists.txt +++ b/panel/CMakeLists.txt @@ -74,7 +74,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 +102,7 @@ add_executable(${PROJECT} target_link_libraries(${PROJECT} ${LIBRARIES} ${QTX_LIBRARIES} - KF5::WindowSystem + KF6::WindowSystem ${STATIC_PLUGINS} ) 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-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-kbindicator/CMakeLists.txt b/plugin-kbindicator/CMakeLists.txt index ab1d45d53..0a5e36192 100644 --- a/plugin-kbindicator/CMakeLists.txt +++ b/plugin-kbindicator/CMakeLists.txt @@ -31,7 +31,7 @@ set(LIBRARIES 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-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-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-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-statusnotifier/CMakeLists.txt b/plugin-statusnotifier/CMakeLists.txt index d12a0f051..eaeb09654 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-qt6 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-qt6 + Qt6::Concurrent ) BUILD_LXQT_PLUGIN(${PLUGIN}) 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-taskbar/CMakeLists.txt b/plugin-taskbar/CMakeLists.txt index 4f7b34dc3..1d627f23e 100644 --- a/plugin-taskbar/CMakeLists.txt +++ b/plugin-taskbar/CMakeLists.txt @@ -25,7 +25,7 @@ set(UIS set(LIBRARIES lxqt lxqt-globalkeys - Qt5Xdg + Qt6Xdg ) BUILD_LXQT_PLUGIN(${PLUGIN}) 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) From b4fe3351f29342b99d79ae95b23a8f4df52251b8 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Thu, 22 Feb 2024 15:25:34 +0100 Subject: [PATCH 03/92] CMake: link to dbusmenu-lxqt instead of dbusmenu-qt6 StatusNotifierButton: switch to dbusmenu-lxqt --- plugin-statusnotifier/CMakeLists.txt | 4 ++-- plugin-statusnotifier/statusnotifierbutton.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin-statusnotifier/CMakeLists.txt b/plugin-statusnotifier/CMakeLists.txt index eaeb09654..76882bc35 100644 --- a/plugin-statusnotifier/CMakeLists.txt +++ b/plugin-statusnotifier/CMakeLists.txt @@ -1,7 +1,7 @@ set(PLUGIN "statusnotifier") -find_package(dbusmenu-qt6 REQUIRED) +find_package(dbusmenu-lxqt REQUIRED) find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Concurrent) set(HEADERS @@ -43,7 +43,7 @@ set_source_files_properties(${DBUS_SOURCES} PROPERTIES SKIP_AUTOGEN ON) list(APPEND SOURCES "${DBUS_SOURCES}") set(LIBRARIES - dbusmenu-qt6 + dbusmenu-lxqt Qt6::Concurrent ) 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 From 96a6dc6c37369fb297e9f8e1b2da9aaf9a24be8c Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 13:04:30 +0100 Subject: [PATCH 04/92] Replace qAsConst() with std::as_const --- panel/lxqtpanelapplication.cpp | 8 ++++---- panel/lxqtpanellayout.cpp | 2 +- panel/panelpluginsmodel.cpp | 2 +- panel/plugin.cpp | 2 +- plugin-fancymenu/lxqtfancymenuappmap.cpp | 2 +- plugin-statusnotifier/statusnotifierwidget.cpp | 2 +- plugin-taskbar/lxqttaskgroup.cpp | 18 +++++++++--------- plugin-volume/alsaengine.cpp | 2 +- plugin-volume/lxqtvolumeconfiguration.cpp | 2 +- plugin-volume/pulseaudioengine.cpp | 2 +- plugin-worldclock/lxqtworldclock.cpp | 2 +- .../lxqtworldclockconfiguration.cpp | 2 +- 12 files changed, 23 insertions(+), 23 deletions(-) diff --git a/panel/lxqtpanelapplication.cpp b/panel/lxqtpanelapplication.cpp index c6e264839..22cd97d81 100644 --- a/panel/lxqtpanelapplication.cpp +++ b/panel/lxqtpanelapplication.cpp @@ -131,7 +131,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 +199,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 +246,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) @@ -300,7 +300,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/lxqtpanellayout.cpp b/panel/lxqtpanellayout.cpp index 29af42ade..d304c8e23 100644 --- a/panel/lxqtpanellayout.cpp +++ b/panel/lxqtpanellayout.cpp @@ -218,7 +218,7 @@ void LayoutItemGrid::rebuild() { clear(); - for(QLayoutItem *item : qAsConst(mItems)) + for(QLayoutItem *item : std::as_const(mItems)) { doAddToGrid(item); } 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/plugin.cpp b/panel/plugin.cpp index d5c8c992e..eb7cfcfa9 100644 --- a/panel/plugin.cpp +++ b/panel/plugin.cpp @@ -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()) diff --git a/plugin-fancymenu/lxqtfancymenuappmap.cpp b/plugin-fancymenu/lxqtfancymenuappmap.cpp index e0b461980..838550a6f 100644 --- a/plugin-fancymenu/lxqtfancymenuappmap.cpp +++ b/plugin-fancymenu/lxqtfancymenuappmap.cpp @@ -237,7 +237,7 @@ QVector LXQtFancyMenuAppMap::getMatchingAp //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)) { diff --git a/plugin-statusnotifier/statusnotifierwidget.cpp b/plugin-statusnotifier/statusnotifierwidget.cpp index d71cca731..5dd98015f 100644 --- a/plugin-statusnotifier/statusnotifierwidget.cpp +++ b/plugin-statusnotifier/statusnotifierwidget.cpp @@ -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-taskbar/lxqttaskgroup.cpp b/plugin-taskbar/lxqttaskgroup.cpp index b7dd7236e..b92ac1eab 100644 --- a/plugin-taskbar/lxqttaskgroup.cpp +++ b/plugin-taskbar/lxqttaskgroup.cpp @@ -96,7 +96,7 @@ void LXQtTaskGroup::contextMenuEvent(QContextMenuEvent *event) ************************************************/ void LXQtTaskGroup::closeGroup() { - for (LXQtTaskButton *button : qAsConst(mButtonHash) ) + for (LXQtTaskButton *button : std::as_const(mButtonHash) ) if (button->isOnDesktop(KX11Extras::currentDesktop())) button->closeApplication(); } @@ -132,7 +132,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 +191,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 +283,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; @@ -323,7 +323,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 +368,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,7 +382,7 @@ 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; visible &= taskbar->isShowOnlyCurrentScreenTasks() ? btn->isOnCurrentScreen() : true; @@ -448,7 +448,7 @@ void LXQtTaskGroup::refreshIconsGeometry() return; } - for(LXQtTaskButton *but : qAsConst(mButtonHash)) + for(LXQtTaskButton *but : std::as_const(mButtonHash)) { but->refreshIconGeometry(rect); but->setIconSize(QSize(plugin()->panel()->iconSize(), plugin()->panel()->iconSize())); @@ -492,7 +492,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*/; } 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..28cc7ff99 100644 --- a/plugin-volume/pulseaudioengine.cpp +++ b/plugin-volume/pulseaudioengine.cpp @@ -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-worldclock/lxqtworldclock.cpp b/plugin-worldclock/lxqtworldclock.cpp index f9ef5e1c6..56513735c 100644 --- a/plugin-worldclock/lxqtworldclock.cpp +++ b/plugin-worldclock/lxqtworldclock.cpp @@ -457,7 +457,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()); 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; From bfcf78a0dc18ed4a35a9e7c492671c0fb6a7360c Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 13:15:18 +0100 Subject: [PATCH 05/92] Replace QPair with std::pair --- panel/panelpluginsmodel.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/panel/panelpluginsmodel.h b/panel/panelpluginsmodel.h index d76e9346f..f08bd28ed 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 From 61893fbe7622457e42bd3a0dfb500d868aa4ef68 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 13:10:19 +0100 Subject: [PATCH 06/92] Replace QLatin1Literal with QLatin1String --- plugin-fancymenu/lxqtfancymenuappmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-fancymenu/lxqtfancymenuappmap.cpp b/plugin-fancymenu/lxqtfancymenuappmap.cpp index 838550a6f..aaa392e2d 100644 --- a/plugin-fancymenu/lxqtfancymenuappmap.cpp +++ b/plugin-fancymenu/lxqtfancymenuappmap.cpp @@ -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); From fb5c5c843daaec4c710d80da11139698aa0382d9 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 17:36:26 +0100 Subject: [PATCH 07/92] QEvent: port pos() to position() and globalPos() to globalPosition() - Now returns floating point QPointF, should we keep it instead of rounding and do floating point calculations? --- panel/pluginmoveprocessor.cpp | 2 +- plugin-colorpicker/colorpicker.cpp | 3 ++- plugin-mainmenu/actionview.cpp | 4 ++-- plugin-quicklaunch/quicklaunchbutton.cpp | 4 ++-- plugin-taskbar/lxqtgrouppopup.cpp | 4 ++-- plugin-taskbar/lxqttaskbar.cpp | 4 ++-- plugin-taskbar/lxqttaskbutton.cpp | 8 ++++---- plugin-volume/volumebutton.cpp | 4 ++-- 8 files changed, 17 insertions(+), 16 deletions(-) diff --git a/panel/pluginmoveprocessor.cpp b/panel/pluginmoveprocessor.cpp index 03928dfe9..92ee8a9be 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); diff --git a/plugin-colorpicker/colorpicker.cpp b/plugin-colorpicker/colorpicker.cpp index 0827ceddd..b7c4dc2b9 100644 --- a/plugin-colorpicker/colorpicker.cpp +++ b/plugin-colorpicker/colorpicker.cpp @@ -144,8 +144,9 @@ void ColorPickerWidget::mouseReleaseEvent(QMouseEvent *event) return; WId id = QApplication::desktop()->winId(); - QPixmap pixmap = qApp->primaryScreen()->grabWindow(id, event->globalX(), event->globalY(), 1, 1); + 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)); diff --git a/plugin-mainmenu/actionview.cpp b/plugin-mainmenu/actionview.cpp index f585fcebe..804062af9 100644 --- a/plugin-mainmenu/actionview.cpp +++ b/plugin-mainmenu/actionview.cpp @@ -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-quicklaunch/quicklaunchbutton.cpp b/plugin-quicklaunch/quicklaunchbutton.cpp index 7dd0945e1..b63948faf 100644 --- a/plugin-quicklaunch/quicklaunchbutton.cpp +++ b/plugin-quicklaunch/quicklaunchbutton.cpp @@ -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-taskbar/lxqtgrouppopup.cpp b/plugin-taskbar/lxqtgrouppopup.cpp index 822416865..640d28d17 100644 --- a/plugin-taskbar/lxqtgrouppopup.cpp +++ b/plugin-taskbar/lxqtgrouppopup.cpp @@ -93,14 +93,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; } diff --git a/plugin-taskbar/lxqttaskbar.cpp b/plugin-taskbar/lxqttaskbar.cpp index 0138b4f79..d5247fe03 100644 --- a/plugin-taskbar/lxqttaskbar.cpp +++ b/plugin-taskbar/lxqttaskbar.cpp @@ -154,7 +154,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 +166,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); } diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index 8c63d4db1..48f407a6a 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -223,7 +223,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 +237,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 +253,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 +366,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); diff --git a/plugin-volume/volumebutton.cpp b/plugin-volume/volumebutton.cpp index 95df40460..c690963ee 100644 --- a/plugin-volume/volumebutton.cpp +++ b/plugin-volume/volumebutton.cpp @@ -80,7 +80,7 @@ void VolumeButton::setMixerCommand(const QString &command) void VolumeButton::enterEvent(QEvent *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) From d1c1ce8355fa2817c5c25dcf88ae112eba3fdbc7 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 16:50:52 +0100 Subject: [PATCH 08/92] Fix QWidget::enterEvent(QEnterEvent*) signature --- plugin-qeyes/qeyeswidget.cpp | 2 +- plugin-qeyes/qeyeswidget.h | 2 +- plugin-statusnotifier/statusnotifierwidget.cpp | 2 +- plugin-statusnotifier/statusnotifierwidget.h | 2 +- plugin-taskbar/lxqtgrouppopup.cpp | 2 +- plugin-taskbar/lxqtgrouppopup.h | 2 +- plugin-taskbar/lxqttaskgroup.cpp | 2 +- plugin-taskbar/lxqttaskgroup.h | 2 +- plugin-volume/volumebutton.cpp | 2 +- plugin-volume/volumebutton.h | 2 +- plugin-volume/volumepopup.cpp | 2 +- plugin-volume/volumepopup.h | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) 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-statusnotifier/statusnotifierwidget.cpp b/plugin-statusnotifier/statusnotifierwidget.cpp index 5dd98015f..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(); } 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-taskbar/lxqtgrouppopup.cpp b/plugin-taskbar/lxqtgrouppopup.cpp index 640d28d17..95bcff5d0 100644 --- a/plugin-taskbar/lxqtgrouppopup.cpp +++ b/plugin-taskbar/lxqtgrouppopup.cpp @@ -137,7 +137,7 @@ void LXQtGroupPopup::leaveEvent(QEvent * /*event*/) /************************************************ * ************************************************/ -void LXQtGroupPopup::enterEvent(QEvent * /*event*/) +void LXQtGroupPopup::enterEvent(QEnterEvent * /*event*/) { mCloseTimer.stop(); } diff --git a/plugin-taskbar/lxqtgrouppopup.h b/plugin-taskbar/lxqtgrouppopup.h index 515236c79..acd77189b 100644 --- a/plugin-taskbar/lxqtgrouppopup.h +++ b/plugin-taskbar/lxqtgrouppopup.h @@ -65,7 +65,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/lxqttaskgroup.cpp b/plugin-taskbar/lxqttaskgroup.cpp index b92ac1eab..6a8a65bd8 100644 --- a/plugin-taskbar/lxqttaskgroup.cpp +++ b/plugin-taskbar/lxqttaskgroup.cpp @@ -538,7 +538,7 @@ void LXQtTaskGroup::leaveEvent(QEvent *event) /************************************************ ************************************************/ -void LXQtTaskGroup::enterEvent(QEvent *event) +void LXQtTaskGroup::enterEvent(QEnterEvent *event) { QToolButton::enterEvent(event); diff --git a/plugin-taskbar/lxqttaskgroup.h b/plugin-taskbar/lxqttaskgroup.h index 88dcccb01..33d1d0f52 100644 --- a/plugin-taskbar/lxqttaskgroup.h +++ b/plugin-taskbar/lxqttaskgroup.h @@ -77,7 +77,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-volume/volumebutton.cpp b/plugin-volume/volumebutton.cpp index c690963ee..f10e2d0b6 100644 --- a/plugin-volume/volumebutton.cpp +++ b/plugin-volume/volumebutton.cpp @@ -77,7 +77,7 @@ 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(event->globalPosition().toPoint(), toolTip(), this); 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..74d0416b8 100644 --- a/plugin-volume/volumepopup.cpp +++ b/plugin-volume/volumepopup.cpp @@ -110,7 +110,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; From 190280ca378331a4ffe6e0dbb30ededca254d249 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 15:47:13 +0100 Subject: [PATCH 09/92] QLayou::setContentsMargin() instead of setMargin() - QEyesPlugin: remove deprecated setMargin() call --- plugin-backlight/sliderdialog.cpp | 2 +- plugin-mount/menudiskitem.cpp | 2 +- plugin-mount/popup.cpp | 2 +- plugin-qeyes/qeyes.cpp | 1 - plugin-taskbar/lxqtgrouppopup.cpp | 2 +- plugin-taskbar/lxqttaskbar.cpp | 2 +- plugin-volume/volumepopup.cpp | 2 +- plugin-worldclock/lxqtworldclock.cpp | 2 +- 8 files changed, 7 insertions(+), 8 deletions(-) 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-mount/menudiskitem.cpp b/plugin-mount/menudiskitem.cpp index bf4a52f21..b18ef7b2e 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); diff --git a/plugin-mount/popup.cpp b/plugin-mount/popup.cpp index 66d34db3a..0c70469aa 100644 --- a/plugin-mount/popup.cpp +++ b/plugin-mount/popup.cpp @@ -61,7 +61,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-taskbar/lxqtgrouppopup.cpp b/plugin-taskbar/lxqtgrouppopup.cpp index 95bcff5d0..1e8a63b20 100644 --- a/plugin-taskbar/lxqtgrouppopup.cpp +++ b/plugin-taskbar/lxqtgrouppopup.cpp @@ -55,7 +55,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); diff --git a/plugin-taskbar/lxqttaskbar.cpp b/plugin-taskbar/lxqttaskbar.cpp index d5247fe03..c933e476a 100644 --- a/plugin-taskbar/lxqttaskbar.cpp +++ b/plugin-taskbar/lxqttaskbar.cpp @@ -78,7 +78,7 @@ LXQtTaskBar::LXQtTaskBar(ILXQtPanelPlugin *plugin, QWidget *parent) : setStyle(mStyle); mLayout = new LXQt::GridLayout(this); setLayout(mLayout); - mLayout->setMargin(0); + mLayout->setContentsMargins(QMargins()); mLayout->setStretch(LXQt::GridLayout::StretchHorizontal | LXQt::GridLayout::StretchVertical); realign(); diff --git a/plugin-volume/volumepopup.cpp b/plugin-volume/volumepopup.cpp index 74d0416b8..fed5de0a4 100644 --- a/plugin-volume/volumepopup.cpp +++ b/plugin-volume/volumepopup.cpp @@ -75,7 +75,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); diff --git a/plugin-worldclock/lxqtworldclock.cpp b/plugin-worldclock/lxqtworldclock.cpp index 56513735c..83a64bc11 100644 --- a/plugin-worldclock/lxqtworldclock.cpp +++ b/plugin-worldclock/lxqtworldclock.cpp @@ -622,7 +622,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() From b8b33c6b0358c7be982f630fb98dae9db4a11b31 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 16:48:20 +0100 Subject: [PATCH 10/92] QuickLaunchButton: fix ambiguous list initializer --- plugin-quicklaunch/quicklaunchbutton.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-quicklaunch/quicklaunchbutton.cpp b/plugin-quicklaunch/quicklaunchbutton.cpp index b63948faf..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()); } From 79c4a4817a9790b68250fc4484c10a59dbe32366 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 17:18:10 +0100 Subject: [PATCH 11/92] Port QRegExp with QRegularExpression TODO TODO: check if syntax is correct and equivalent --- plugin-sysstat/lxqtsysstatutils.cpp | 13 +++++++------ plugin-sysstat/lxqtsysstatutils.h | 2 +- plugin-worldclock/lxqtworldclock.cpp | 7 +++++-- 3 files changed, 13 insertions(+), 9 deletions(-) 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-worldclock/lxqtworldclock.cpp b/plugin-worldclock/lxqtworldclock.cpp index 83a64bc11..6db18df63 100644 --- a/plugin-worldclock/lxqtworldclock.cpp +++ b/plugin-worldclock/lxqtworldclock.cpp @@ -165,6 +165,8 @@ void LXQtWorldClock::restartTimer() void LXQtWorldClock::settingsChanged() { + static QRegularExpression regexp(QLatin1String("'[^']*'")); + PluginSettings *_settings = settings(); QString oldFormat = mFormat; @@ -324,7 +326,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; @@ -476,7 +478,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); } From cb2d7cbcd7aba13e6ae7d10c585d2e689550eb7b Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 17:38:52 +0100 Subject: [PATCH 12/92] QLocale territory() instead of country() --- plugin-worldclock/lxqtworldclockconfigurationtimezones.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); From a955bb6796e5691b787891fbf115a0ecdb55ceca Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 17:39:45 +0100 Subject: [PATCH 13/92] Qt6 always enables High-DPI Pixmaps Qt::AA_UseHighDpiPixmaps has no effect now --- panel/main.cpp | 1 - 1 file changed, 1 deletion(-) 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(); } From e37056f69f4b8a11657487911d77c83d666bbe1b Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 17:48:40 +0100 Subject: [PATCH 14/92] PanelPluginsModel: Q_DECLARE_OPAQUE_POINTER() Not sure about this but I get: error: static assertion failed: Pointer Meta Types must either point to fully-defined types or be declared with Q_DECLARE_OPAQUE_POINTER(T *) --- panel/panelpluginsmodel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panel/panelpluginsmodel.h b/panel/panelpluginsmodel.h index f08bd28ed..a31bf2ad1 100644 --- a/panel/panelpluginsmodel.h +++ b/panel/panelpluginsmodel.h @@ -336,6 +336,6 @@ public slots: LXQtPanel * mPanel; }; -Q_DECLARE_METATYPE(Plugin const *) +Q_DECLARE_OPAQUE_POINTER(Plugin const *) #endif // PANELPLUGINSMODEL_H From b838c60e144443c003fecd6aef34a2c348bea905 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 17:50:43 +0100 Subject: [PATCH 15/92] Use QColor::fromString() setNamedColor() is deprecated in Qt6 --- panel/config/configstyling.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/panel/config/configstyling.cpp b/panel/config/configstyling.cpp index b30d3c80f..760ea3885 100644 --- a/panel/config/configstyling.cpp +++ b/panel/config/configstyling.cpp @@ -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(); } From 06004442bc2821339a557bf0d08497f7d1197ea0 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 17:24:52 +0100 Subject: [PATCH 16/92] FIXME: LXQtTaskButton deprecated constructor Code is hacky, find better solution --- plugin-taskbar/lxqttaskbutton.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index 48f407a6a..d5f36e7f7 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -395,7 +395,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; From 741d2d7d75b45d8332f4a751181ac65964272e84 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 12:25:41 +0100 Subject: [PATCH 17/92] Disable ColorPicker on Wayland --- plugin-colorpicker/colorpicker.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/plugin-colorpicker/colorpicker.cpp b/plugin-colorpicker/colorpicker.cpp index b7c4dc2b9..04f800421 100644 --- a/plugin-colorpicker/colorpicker.cpp +++ b/plugin-colorpicker/colorpicker.cpp @@ -29,7 +29,6 @@ #include "colorpicker.h" #include #include -#include #include #include #include @@ -143,12 +142,22 @@ void ColorPickerWidget::mouseReleaseEvent(QMouseEvent *event) if (!mCapturing) return; - WId id = QApplication::desktop()->winId(); + QColor col; - 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)); + if (auto *x11Application = qGuiApp->nativeInterface()) + { + Q_UNUSED(x11Application); + //FIXME: QDesktopWidget is not available in Qt6, screens have not WId + WId id = 0; /*QApplication::desktop()->winId();*/ + QPixmap pixmap = qApp->primaryScreen()->grabWindow(id, event->globalPos().x(), event->globalPos().y(), 1, 1); + + QImage img = pixmap.toImage(); + col = QColor(img.pixel(0,0)); + } + else + { + qWarning() << "WAYLAND does not support grabbing windows"; + } mColorButton->setColor(col); paste(col.name()); From a0b3ce37f154c2aabe4f73613ed06c0251be6993 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 15:47:24 +0100 Subject: [PATCH 18/92] Fix KX11Extras, KWindowSystem includes TODO: Still don't know why prefix does not work - Remove includes to QDesktopWidget --- panel/config/configplacement.cpp | 2 +- panel/config/configstyling.cpp | 2 +- panel/lxqtpanel.cpp | 10 +++++----- panel/plugin.cpp | 2 +- plugin-mainmenu/lxqtmainmenu.cpp | 1 + plugin-mount/popup.cpp | 1 - plugin-showdesktop/showdesktop.cpp | 5 ++--- plugin-volume/volumepopup.cpp | 1 - plugin-worldclock/lxqtworldclock.cpp | 1 - 9 files changed, 11 insertions(+), 14 deletions(-) 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/configstyling.cpp b/panel/config/configstyling.cpp index 760ea3885..7035a636d 100644 --- a/panel/config/configstyling.cpp +++ b/panel/config/configstyling.cpp @@ -30,7 +30,7 @@ #include "../lxqtpanellimits.h" -#include +#include #include #include #include diff --git a/panel/lxqtpanel.cpp b/panel/lxqtpanel.cpp index 05d903089..127e2a8e4 100644 --- a/panel/lxqtpanel.cpp +++ b/panel/lxqtpanel.cpp @@ -40,7 +40,6 @@ #include #include -#include #include #include #include @@ -49,9 +48,10 @@ #include #include -#include -#include -#include +#include +#include +#include +#include // Turn on this to show the time required to load each plugin during startup // #define DEBUG_PLUGIN_LOADTIME @@ -1127,7 +1127,7 @@ bool LXQtPanel::event(QEvent *event) // 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); + KX11Extras::setType(effectiveWinId(), NET::Dock); updateWmStrut(); // reserve screen space for the panel KX11Extras::setOnAllDesktops(effectiveWinId(), true); diff --git a/panel/plugin.cpp b/panel/plugin.cpp index eb7cfcfa9..eb22ed431 100644 --- a/panel/plugin.cpp +++ b/panel/plugin.cpp @@ -31,7 +31,7 @@ #include "pluginsettings_p.h" #include "lxqtpanel.h" -#include +#include #include #include diff --git a/plugin-mainmenu/lxqtmainmenu.cpp b/plugin-mainmenu/lxqtmainmenu.cpp index a689db423..1db7f911f 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/popup.cpp b/plugin-mount/popup.cpp index 0c70469aa..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 diff --git a/plugin-showdesktop/showdesktop.cpp b/plugin-showdesktop/showdesktop.cpp index 1733489d2..871da62ea 100644 --- a/plugin-showdesktop/showdesktop.cpp +++ b/plugin-showdesktop/showdesktop.cpp @@ -26,12 +26,11 @@ * END_COMMON_COPYRIGHT_HEADER */ #include -#include #include #include #include -#include -#include +#include +#include #include "showdesktop.h" #include "../panel/pluginsettings.h" diff --git a/plugin-volume/volumepopup.cpp b/plugin-volume/volumepopup.cpp index fed5de0a4..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 diff --git a/plugin-worldclock/lxqtworldclock.cpp b/plugin-worldclock/lxqtworldclock.cpp index 6db18df63..b5557bdd2 100644 --- a/plugin-worldclock/lxqtworldclock.cpp +++ b/plugin-worldclock/lxqtworldclock.cpp @@ -32,7 +32,6 @@ #include #include -#include #include #include #include From cbad6795973a07a580800524ea6789b2926b1d1d Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 9 Feb 2024 12:34:57 +0100 Subject: [PATCH 19/92] Port QX11Info to QX11Application NOTE: Fix compilation with Xlib.h Xlib.h is tricky because at line 82 has: `#define Bool int` And QtCore/qjsonvalue.h at line 28 has: ``` enum Type { ... Bool = 0x1, ... } ``` This is fixed temporarily by moving Xlib.h include to last and undefine Bool macro Long term we want to hide X11 related code and encapsulate in a backend. This backend will not expose X11 headers. --- plugin-colorpicker/colorpicker.cpp | 11 ++- plugin-desktopswitch/desktopswitch.cpp | 25 ++++-- plugin-desktopswitch/desktopswitch.h | 2 +- .../desktopswitchconfiguration.cpp | 2 +- plugin-taskbar/lxqttaskbar.cpp | 11 ++- plugin-taskbar/lxqttaskbar.h | 6 +- plugin-taskbar/lxqttaskbarconfiguration.cpp | 2 +- plugin-taskbar/lxqttaskbutton.cpp | 90 ++++++++++++++++--- plugin-taskbar/lxqttaskgroup.cpp | 25 ++++-- plugin-taskbar/lxqttaskgroup.h | 2 +- 10 files changed, 139 insertions(+), 37 deletions(-) diff --git a/plugin-colorpicker/colorpicker.cpp b/plugin-colorpicker/colorpicker.cpp index 04f800421..6ee97cba1 100644 --- a/plugin-colorpicker/colorpicker.cpp +++ b/plugin-colorpicker/colorpicker.cpp @@ -36,6 +36,10 @@ #include #include +//NOTE: Xlib.h defines Bool which conflicts with QJsonValue::Type enum +#include +#undef Bool + const QString ColorPickerWidget::svgIcon = QStringLiteral( "" @@ -146,10 +150,9 @@ void ColorPickerWidget::mouseReleaseEvent(QMouseEvent *event) if (auto *x11Application = qGuiApp->nativeInterface()) { - Q_UNUSED(x11Application); - //FIXME: QDesktopWidget is not available in Qt6, screens have not WId - WId id = 0; /*QApplication::desktop()->winId();*/ - QPixmap pixmap = qApp->primaryScreen()->grabWindow(id, event->globalPos().x(), event->globalPos().y(), 1, 1); + 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(); col = QColor(img.pixel(0,0)); diff --git a/plugin-desktopswitch/desktopswitch.cpp b/plugin-desktopswitch/desktopswitch.cpp index 380efdf9c..4bd05e08f 100644 --- a/plugin-desktopswitch/desktopswitch.cpp +++ b/plugin-desktopswitch/desktopswitch.cpp @@ -32,15 +32,22 @@ #include #include #include -#include -#include -#include + + #include #include "desktopswitch.h" #include "desktopswitchbutton.h" #include "desktopswitchconfiguration.h" +#include +#include +#include + +//NOTE: Xlib.h defines Bool which conflicts with QJsonValue::Type enum +#include +#undef Bool + static const QString DEFAULT_SHORTCUT_TEMPLATE(QStringLiteral("Control+F%1")); DesktopSwitch::DesktopSwitch(const ILXQtPanelPluginStartupInfo &startupInfo) : @@ -50,9 +57,13 @@ DesktopSwitch::DesktopSwitch(const ILXQtPanelPluginStartupInfo &startupInfo) : m_desktopCount(KX11Extras::numberOfDesktops()), mRows(-1), mShowOnlyActive(false), - mDesktops(new NETRootInfo(QX11Info::connection(), NET::NumberOfDesktops | NET::CurrentDesktop | NET::DesktopNames, NET::WM2DesktopLayout)), + mDesktops(nullptr), mLabelType(static_cast(-1)) { + auto *x11Application = qGuiApp->nativeInterface(); + Q_ASSERT_X(x11Application, "DesktopSwitch", "Expected X11 connection"); + mDesktops.reset(new NETRootInfo(x11Application->connection(), NET::NumberOfDesktops | NET::CurrentDesktop | NET::DesktopNames, NET::WM2DesktopLayout)); + m_buttons = new QButtonGroup(this); connect (m_pSignalMapper, &QSignalMapper::mappedInt, this, &DesktopSwitch::setDesktop); @@ -196,9 +207,13 @@ bool DesktopSwitch::isWindowHighlightable(WId window) if (info.state() & NET::SkipTaskbar) return false; + auto *x11Application = qGuiApp->nativeInterface(); + Q_ASSERT_X(x11Application, "DesktopSwitch", "Expected X11 connection"); + WId appRootWindow = XDefaultRootWindow(x11Application->display()); + // WM_TRANSIENT_FOR hint not set - normal window WId transFor = info.transientFor(); - if (transFor == 0 || transFor == window || transFor == (WId) QX11Info::appRootWindow()) + if (transFor == 0 || transFor == window || transFor == appRootWindow) return true; info = KWindowInfo(transFor, NET::WMWindowType); diff --git a/plugin-desktopswitch/desktopswitch.h b/plugin-desktopswitch/desktopswitch.h index 73d7a9e78..c317ddbae 100644 --- a/plugin-desktopswitch/desktopswitch.h +++ b/plugin-desktopswitch/desktopswitch.h @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include "desktopswitchbutton.h" diff --git a/plugin-desktopswitch/desktopswitchconfiguration.cpp b/plugin-desktopswitch/desktopswitchconfiguration.cpp index 402981467..943dbdd6b 100644 --- a/plugin-desktopswitch/desktopswitchconfiguration.cpp +++ b/plugin-desktopswitch/desktopswitchconfiguration.cpp @@ -26,7 +26,7 @@ #include "desktopswitchconfiguration.h" #include "ui_desktopswitchconfiguration.h" -#include +#include #include DesktopSwitchConfiguration::DesktopSwitchConfiguration(PluginSettings *settings, QWidget *parent) : diff --git a/plugin-taskbar/lxqttaskbar.cpp b/plugin-taskbar/lxqttaskbar.cpp index c933e476a..7544a0b43 100644 --- a/plugin-taskbar/lxqttaskbar.cpp +++ b/plugin-taskbar/lxqttaskbar.cpp @@ -37,7 +37,6 @@ #include #include #include -#include #include #include @@ -47,6 +46,10 @@ #include "lxqttaskbar.h" #include "lxqttaskgroup.h" +//NOTE: Xlib.h defines Bool which conflicts with QJsonValue::Type enum +#include +#undef Bool + using namespace LXQt; /************************************************ @@ -131,9 +134,13 @@ bool LXQtTaskBar::acceptWindow(WId window) const if (info.state() & NET::SkipTaskbar) return false; + auto *x11Application = qGuiApp->nativeInterface(); + Q_ASSERT_X(x11Application, "DesktopSwitch", "Expected X11 connection"); + WId appRootWindow = XDefaultRootWindow(x11Application->display()); + // WM_TRANSIENT_FOR hint not set - normal window WId transFor = info.transientFor(); - if (transFor == 0 || transFor == window || transFor == (WId) QX11Info::appRootWindow()) + if (transFor == 0 || transFor == window || transFor == appRootWindow) return true; info = KWindowInfo(transFor, NET::WMWindowType); diff --git a/plugin-taskbar/lxqttaskbar.h b/plugin-taskbar/lxqttaskbar.h index 5b2e79e7a..959b3286f 100644 --- a/plugin-taskbar/lxqttaskbar.h +++ b/plugin-taskbar/lxqttaskbar.h @@ -43,9 +43,9 @@ #include #include #include "../panel/ilxqtpanel.h" -#include -#include -#include +#include +#include +#include class QSignalMapper; class LXQtTaskButton; diff --git a/plugin-taskbar/lxqttaskbarconfiguration.cpp b/plugin-taskbar/lxqttaskbarconfiguration.cpp index 267d20e8c..b346bb69d 100644 --- a/plugin-taskbar/lxqttaskbarconfiguration.cpp +++ b/plugin-taskbar/lxqttaskbarconfiguration.cpp @@ -29,7 +29,7 @@ #include "lxqttaskbarconfiguration.h" #include "ui_lxqttaskbarconfiguration.h" -#include +#include LXQtTaskbarConfiguration::LXQtTaskbarConfiguration(PluginSettings *settings, QWidget *parent): LXQtPanelPluginConfigDialog(settings, parent), diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index d5f36e7f7..e6ead3ba8 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -47,17 +47,20 @@ #include #include #include -#include #include #include "lxqttaskbutton.h" #include "lxqttaskgroup.h" #include "lxqttaskbar.h" -#include +#include // Necessary for closeApplication() -#include -#include +#include +#include + +//NOTE: Xlib.h defines Bool which conflicts with QJsonValue::Type enum +#include +#undef Bool bool LXQtTaskButton::sDraggging = false; @@ -115,8 +118,18 @@ 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)); + auto *x11Application = qGuiApp->nativeInterface(); + if(x11Application) + { + WId appRootWindow = XDefaultRootWindow(x11Application->display()); + setUrgencyHint(NETWinInfo(x11Application->connection(), mWindow, appRootWindow, NET::Properties{}, NET::WM2Urgency).urgency() + || KWindowInfo{mWindow, NET::WMState}.hasState(NET::DemandsAttention)); + } + else + { + qWarning() << "LXQtTaskBar: not implemented on Wayland"; + } + connect(LXQt::Settings::globalSettings(), &LXQt::GlobalSettings::iconThemeChanged, this, &LXQtTaskButton::updateIcon); connect(mParentTaskBar, &LXQtTaskBar::iconByClassChanged, this, &LXQtTaskButton::updateIcon); @@ -164,7 +177,21 @@ 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(); + WId appRootWindow = 0; + xcb_connection_t* x11conn = nullptr; + + auto *x11Application = qGuiApp->nativeInterface(); + if(x11Application) + { + appRootWindow = XDefaultRootWindow(x11Application->display()); + x11conn = x11Application->connection(); + } + else + { + //qWarning() << "LXQtTaskBar: not implemented on Wayland"; + return; + } + if (!x11conn) { return; @@ -172,7 +199,7 @@ void LXQtTaskButton::refreshIconGeometry(QRect const & geom) NETWinInfo info(x11conn, windowId(), - (WId) QX11Info::appRootWindow(), + appRootWindow, NET::WMIconGeometry, NET::Properties2()); NETRect const curr = info.iconGeometry(); @@ -510,8 +537,16 @@ void LXQtTaskButton::unShadeApplication() ************************************************/ void LXQtTaskButton::closeApplication() { - // FIXME: Why there is no such thing in KWindowSystem?? - NETRootInfo(QX11Info::connection(), NET::CloseWindow).closeWindowRequest(mWindow); + auto *x11Application = qGuiApp->nativeInterface(); + if(x11Application) + { + // FIXME: Why there is no such thing in KWindowSystem?? + NETRootInfo(x11Application->connection(), NET::CloseWindow).closeWindowRequest(mWindow); + } + else + { + qWarning() << "LXQtTaskBar: not implemented on Wayland"; + } } /************************************************ @@ -610,7 +645,18 @@ void LXQtTaskButton::moveApplicationToPrevNextMonitor(bool next) // 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); + + + auto *x11Application = qGuiApp->nativeInterface(); + if(x11Application) + { + NETRootInfo(x11Application->connection(), NET::Properties(), NET::WM2MoveResizeWindow).moveResizeWindowRequest(mWindow, flags, X, Y, 0, 0); + } + else + { + //qWarning() << "LXQtTaskBar: not implemented on Wayland"; + } + QTimer::singleShot(200, this, [this, state] { KWindowSystem::setState(mWindow, state); @@ -637,7 +683,16 @@ void LXQtTaskButton::moveApplication() 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); + + auto *x11Application = qGuiApp->nativeInterface(); + if(x11Application) + { + NETRootInfo(x11Application->connection(), NET::WMMoveResize).moveResizeRequest(mWindow, X, Y, NET::Move); + } + else + { + //qWarning() << "LXQtTaskBar: not implemented on Wayland"; + } } /************************************************ @@ -655,7 +710,16 @@ void LXQtTaskButton::resizeApplication() 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); + + auto *x11Application = qGuiApp->nativeInterface(); + if(x11Application) + { + NETRootInfo(x11Application->connection(), NET::WMMoveResize).moveResizeRequest(mWindow, X, Y, NET::BottomRight); + } + else + { + //qWarning() << "LXQtTaskBar: not implemented on Wayland"; + } } /************************************************ diff --git a/plugin-taskbar/lxqttaskgroup.cpp b/plugin-taskbar/lxqttaskgroup.cpp index 6a8a65bd8..2bd7e18b0 100644 --- a/plugin-taskbar/lxqttaskgroup.cpp +++ b/plugin-taskbar/lxqttaskgroup.cpp @@ -38,10 +38,12 @@ #include #include #include -#include -#include #include +#include //For nativeInterface() +#include +#include + /************************************************ ************************************************/ @@ -657,18 +659,29 @@ bool LXQtTaskGroup::onWindowChanged(WId window, NET::Properties prop, NET::Prope bool set_urgency = false; bool urgency = false; + + if (auto *x11Application = qGuiApp->nativeInterface()) + { + WId appRootWindow = XDefaultRootWindow(x11Application->display()); + urgency = NETWinInfo(x11Application->connection(), window, appRootWindow, NET::Properties{}, NET::WM2Urgency).urgency(); + } + if (prop2.testFlag(NET::WM2Urgency)) { set_urgency = true; - urgency = NETWinInfo(QX11Info::connection(), window, QX11Info::appRootWindow(), NET::Properties{}, NET::WM2Urgency).urgency(); } if (prop.testFlag(NET::WMState)) { KWindowInfo info{window, NET::WMState}; + + // Force refresh urgency 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))); - set_urgency = false; + { + //TODO: maybe do it in common place with NET::WM2Urgency + std::for_each(buttons.begin(), buttons.end(), std::bind(&LXQtTaskButton::setUrgencyHint, std::placeholders::_1, urgency || info.hasState(NET::DemandsAttention))); + set_urgency = false; + } + if (info.hasState(NET::SkipTaskbar)) onWindowRemoved(window); diff --git a/plugin-taskbar/lxqttaskgroup.h b/plugin-taskbar/lxqttaskgroup.h index 33d1d0f52..cd79d0716 100644 --- a/plugin-taskbar/lxqttaskgroup.h +++ b/plugin-taskbar/lxqttaskgroup.h @@ -36,7 +36,7 @@ #include "lxqttaskbar.h" #include "lxqtgrouppopup.h" #include "lxqttaskbutton.h" -#include +#include class QVBoxLayout; class ILXQtPanelPlugin; From 1ef5229f5baa12217d48acda27e4b6a8dcb940e5 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 11 Feb 2024 10:15:32 +0100 Subject: [PATCH 20/92] LXQtTaskButton: port to KX11Extras Many X11 specific functions got moved away from KWindowSystem header. Long term we will move everything to a backend. --- plugin-taskbar/lxqttaskbutton.cpp | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index e6ead3ba8..17b8f8ec8 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -56,7 +56,6 @@ #include // Necessary for closeApplication() #include -#include //NOTE: Xlib.h defines Bool which conflicts with QJsonValue::Type enum #include @@ -489,15 +488,15 @@ void LXQtTaskButton::maximizeApplication() switch (state) { case NET::MaxHoriz: - KWindowSystem::setState(mWindow, NET::MaxHoriz); + KX11Extras::setState(mWindow, NET::MaxHoriz); break; case NET::MaxVert: - KWindowSystem::setState(mWindow, NET::MaxVert); + KX11Extras::setState(mWindow, NET::MaxVert); break; default: - KWindowSystem::setState(mWindow, NET::Max); + KX11Extras::setState(mWindow, NET::Max); break; } @@ -510,7 +509,7 @@ void LXQtTaskButton::maximizeApplication() ************************************************/ void LXQtTaskButton::deMaximizeApplication() { - KWindowSystem::clearState(mWindow, NET::Max); + KX11Extras::clearState(mWindow, NET::Max); if (!isApplicationActive()) raiseApplication(); @@ -521,7 +520,7 @@ void LXQtTaskButton::deMaximizeApplication() ************************************************/ void LXQtTaskButton::shadeApplication() { - KWindowSystem::setState(mWindow, NET::Shaded); + KX11Extras::setState(mWindow, NET::Shaded); } /************************************************ @@ -529,7 +528,7 @@ void LXQtTaskButton::shadeApplication() ************************************************/ void LXQtTaskButton::unShadeApplication() { - KWindowSystem::clearState(mWindow, NET::Shaded); + KX11Extras::clearState(mWindow, NET::Shaded); } /************************************************ @@ -540,7 +539,7 @@ void LXQtTaskButton::closeApplication() auto *x11Application = qGuiApp->nativeInterface(); if(x11Application) { - // FIXME: Why there is no such thing in KWindowSystem?? + // FIXME: Why there is no such thing in KX11Extras?? NETRootInfo(x11Application->connection(), NET::CloseWindow).closeWindowRequest(mWindow); } else @@ -562,18 +561,18 @@ void LXQtTaskButton::setApplicationLayer() switch(layer) { case NET::KeepAbove: - KWindowSystem::clearState(mWindow, NET::KeepBelow); - KWindowSystem::setState(mWindow, NET::KeepAbove); + KX11Extras::clearState(mWindow, NET::KeepBelow); + KX11Extras::setState(mWindow, NET::KeepAbove); break; case NET::KeepBelow: - KWindowSystem::clearState(mWindow, NET::KeepAbove); - KWindowSystem::setState(mWindow, NET::KeepBelow); + KX11Extras::clearState(mWindow, NET::KeepAbove); + KX11Extras::setState(mWindow, NET::KeepBelow); break; default: - KWindowSystem::clearState(mWindow, NET::KeepBelow); - KWindowSystem::clearState(mWindow, NET::KeepAbove); + KX11Extras::clearState(mWindow, NET::KeepBelow); + KX11Extras::clearState(mWindow, NET::KeepAbove); break; } } @@ -644,7 +643,7 @@ void LXQtTaskButton::moveApplicationToPrevNextMonitor(bool next) 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); + KX11Extras::clearState(mWindow, NET::MaxHoriz | NET::MaxVert | NET::Max | NET::FullScreen); auto *x11Application = qGuiApp->nativeInterface(); @@ -659,7 +658,7 @@ void LXQtTaskButton::moveApplicationToPrevNextMonitor(bool next) QTimer::singleShot(200, this, [this, state] { - KWindowSystem::setState(mWindow, state); + KX11Extras::setState(mWindow, state); raiseApplication(); }); break; From 606a223e0f189334f1d77992a4f39361213dc864 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 11 Feb 2024 10:18:23 +0100 Subject: [PATCH 21/92] LXQtTaskButton: port away from QDesktopWidget Use QScreen instead --- plugin-taskbar/lxqttaskbutton.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index 17b8f8ec8..3bcc7ee5b 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -913,7 +913,11 @@ bool LXQtTaskButton::isOnDesktop(int desktop) const bool LXQtTaskButton::isOnCurrentScreen() const { - return QApplication::desktop()->screenGeometry(parentTaskBar()).intersects(KWindowInfo(mWindow, NET::WMFrameExtents).frameGeometry()); + QScreen *screen = parentTaskBar()->screen(); + QRect screenGeo = screen->geometry(); + QRect windowGeo = KWindowInfo(mWindow, NET::WMFrameExtents).frameGeometry(); + + return screenGeo.intersects(windowGeo); } bool LXQtTaskButton::isMinimized() const From 27c93d8630d16ce5a00960920082bbfb13b1de47 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 11 Feb 2024 11:08:17 +0100 Subject: [PATCH 22/92] QString::arg(...) use mult-arg version Reported by Clazy --- panel/pluginmoveprocessor.cpp | 4 +--- plugin-colorpicker/colorpicker.cpp | 2 +- plugin-mount/menudiskitem.cpp | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/panel/pluginmoveprocessor.cpp b/panel/pluginmoveprocessor.cpp index 92ee8a9be..dfb0d3632 100644 --- a/panel/pluginmoveprocessor.cpp +++ b/panel/pluginmoveprocessor.cpp @@ -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/plugin-colorpicker/colorpicker.cpp b/plugin-colorpicker/colorpicker.cpp index 6ee97cba1..004314557 100644 --- a/plugin-colorpicker/colorpicker.cpp +++ b/plugin-colorpicker/colorpicker.cpp @@ -198,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-mount/menudiskitem.cpp b/plugin-mount/menudiskitem.cpp index b18ef7b2e..3f4af34ab 100644 --- a/plugin-mount/menudiskitem.cpp +++ b/plugin-mount/menudiskitem.cpp @@ -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()); } } From 61a051daa09cd8f107292dfe469816c06ad99ac6 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 11 Feb 2024 11:10:45 +0100 Subject: [PATCH 23/92] LXQtCpuLoad: do not include directly Reported by Clazy --- plugin-cpuload/lxqtcpuload.cpp | 1 - 1 file changed, 1 deletion(-) 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 From 70d580c4011da01ba9467f5cbfd0628af2083f08 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 11 Feb 2024 11:19:23 +0100 Subject: [PATCH 24/92] Configuration: fix call to temporary object Teporary objects get destroyed after call ends. State is not updated. --- plugin-mount/configuration.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) 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(); From d0dcf66ab48faf75e03f75e7f54fc6c572feda29 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 11 Feb 2024 11:25:20 +0100 Subject: [PATCH 25/92] QEyesConfigDialog: avoid allocating temporary container - Reported by Clazy - Also fix formatting a bit --- plugin-qeyes/qeyesconfigdialog.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) 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++; } From 1f7a0fae84bd6f2b696a5270891de18bbc1b3f58 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 11 Feb 2024 11:28:31 +0100 Subject: [PATCH 26/92] QEyesImageWidget: unneeded QString allocation - Use Qt::CaseInsensitive instead - Pass argument by reference - Format braces --- plugin-qeyes/qeyesimagewidget.cpp | 11 ++++++++--- plugin-qeyes/qeyesimagewidget.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) 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(); From 96b98e0a6bd999ff0985f203a0e725f15db132df Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 11 Feb 2024 11:30:33 +0100 Subject: [PATCH 27/92] LXQtQuickLaunch: fix QSet warning and better readability --- plugin-quicklaunch/lxqtquicklaunch.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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); From 7d06f23b69b6ac75229cf97ebdf12540c8b8bbcf Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 11 Feb 2024 13:48:16 +0100 Subject: [PATCH 28/92] Port LXQtTrayPlugin to Qt6 TODO TODO: QX11Info::getTimestamp() was replaced with XCB_CURRENT_TIME macro. I don't know if this breaks functionality. Getting real timestamp involves messing with Qt private APIs --- plugin-tray/fdoselectionmanager.cpp | 50 ++++++----- plugin-tray/fdoselectionmanager.h | 3 +- plugin-tray/lxqttrayplugin.cpp | 15 ++++ plugin-tray/lxqttrayplugin.h | 15 +--- plugin-tray/sniproxy.cpp | 129 +++++++++++++++------------- plugin-tray/sniproxy.h | 1 + plugin-tray/xcbutils.h | 15 ++-- 7 files changed, 126 insertions(+), 102 deletions(-) diff --git a/plugin-tray/fdoselectionmanager.cpp b/plugin-tray/fdoselectionmanager.cpp index 2486257c8..43d02646b 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,15 +109,14 @@ 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 attr(xcb_get_window_attributes_reply(m_connection, attribsCookie, &error)); QScopedPointer getAttrError(error); uint32_t events = XCB_EVENT_MASK_STRUCTURE_NOTIFY; if (!attr.isNull()) { @@ -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); + QScopedPointer 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/sniproxy.cpp b/plugin-tray/sniproxy.cpp index a0c732147..2029ef580 100644 --- a/plugin-tray/sniproxy.cpp +++ b/plugin-tray/sniproxy.cpp @@ -28,27 +28,34 @@ #include "sniproxy.h" #include -#include -#include - -#include "xcbutils.h" #include #include #include #include -#include #include #include #include +#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 +66,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 +79,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 +110,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 +134,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 +144,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 +173,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 +217,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); + QScopedPointer 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 +231,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 +259,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 +275,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); + QScopedPointer clientGeom(xcb_get_geometry_reply(m_connection, cookie, nullptr)); QSize clientWindowSize; if (clientGeom) { @@ -318,11 +327,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; @@ -417,15 +424,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)); + QScopedPointer extentsReply(xcb_shape_query_extents_reply(m_connection, extentsCookie, nullptr)); + QScopedPointer rectanglesReply(xcb_shape_get_rectangles_reply(m_connection, rectaglesCookie, nullptr)); if (!extentsReply || !rectanglesReply || !extentsReply->bounding_shaped) { return clickPoint; @@ -452,9 +457,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 +552,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); + QScopedPointer 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); + QScopedPointer 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 +582,23 @@ 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()); + // 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 = XCB_CURRENT_TIME; //FIXME: how to get proper 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 +607,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 +619,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 = XCB_CURRENT_TIME; //FIXME: how to get proper 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 +630,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..5148f2283 100644 --- a/plugin-tray/xcbutils.h +++ b/plugin-tray/xcbutils.h @@ -37,7 +37,6 @@ #include #include -#include /** XEMBED messages */ #define XEMBED_EMBEDDED_NOTIFY 0 @@ -59,7 +58,7 @@ using ScopedCPointer = QScopedPointer; 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())) @@ -120,12 +119,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) { } From e094680f9e307d2e4979b481e0f1471663da4698 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 11 Feb 2024 16:05:16 +0100 Subject: [PATCH 29/92] LXQtTaskBar: fix include recursion - Forward declare classes - More refactory could be done here --- plugin-taskbar/lxqtgrouppopup.cpp | 12 ++++++++++++ plugin-taskbar/lxqtgrouppopup.h | 9 ++++----- plugin-taskbar/lxqttaskbar.cpp | 1 + plugin-taskbar/lxqttaskbar.h | 7 ++++--- plugin-taskbar/lxqttaskbarplugin.cpp | 2 ++ plugin-taskbar/lxqttaskgroup.cpp | 1 + plugin-taskbar/lxqttaskgroup.h | 3 +-- 7 files changed, 25 insertions(+), 10 deletions(-) diff --git a/plugin-taskbar/lxqtgrouppopup.cpp b/plugin-taskbar/lxqtgrouppopup.cpp index 1e8a63b20..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 @@ -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 acd77189b..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: diff --git a/plugin-taskbar/lxqttaskbar.cpp b/plugin-taskbar/lxqttaskbar.cpp index 7544a0b43..5dfa289c9 100644 --- a/plugin-taskbar/lxqttaskbar.cpp +++ b/plugin-taskbar/lxqttaskbar.cpp @@ -45,6 +45,7 @@ #include "lxqttaskbar.h" #include "lxqttaskgroup.h" +#include "../panel/pluginsettings.h" //NOTE: Xlib.h defines Bool which conflicts with QJsonValue::Type enum #include diff --git a/plugin-taskbar/lxqttaskbar.h b/plugin-taskbar/lxqttaskbar.h index 959b3286f..03e2bd0d2 100644 --- a/plugin-taskbar/lxqttaskbar.h +++ b/plugin-taskbar/lxqttaskbar.h @@ -34,9 +34,6 @@ #include "../panel/ilxqtpanel.h" #include "../panel/ilxqtpanelplugin.h" -#include "lxqttaskbarconfiguration.h" -#include "lxqttaskgroup.h" -#include "lxqttaskbutton.h" #include #include @@ -48,8 +45,12 @@ #include class QSignalMapper; + class LXQtTaskButton; +class LXQtTaskGroup; + class ElidedButtonStyle; +class LeftAlignedTextStyle; namespace LXQt { class GridLayout; diff --git a/plugin-taskbar/lxqttaskbarplugin.cpp b/plugin-taskbar/lxqttaskbarplugin.cpp index 51dc41456..ae8af1403 100644 --- a/plugin-taskbar/lxqttaskbarplugin.cpp +++ b/plugin-taskbar/lxqttaskbarplugin.cpp @@ -28,6 +28,8 @@ #include "lxqttaskbarplugin.h" +#include "lxqttaskbarconfiguration.h" + LXQtTaskBarPlugin::LXQtTaskBarPlugin(const ILXQtPanelPluginStartupInfo &startupInfo): QObject(), ILXQtPanelPlugin(startupInfo) diff --git a/plugin-taskbar/lxqttaskgroup.cpp b/plugin-taskbar/lxqttaskgroup.cpp index 2bd7e18b0..1af953ba7 100644 --- a/plugin-taskbar/lxqttaskgroup.cpp +++ b/plugin-taskbar/lxqttaskgroup.cpp @@ -30,6 +30,7 @@ #include "lxqttaskgroup.h" #include "lxqttaskbar.h" +#include "lxqtgrouppopup.h" #include #include diff --git a/plugin-taskbar/lxqttaskgroup.h b/plugin-taskbar/lxqttaskgroup.h index cd79d0716..f1e7e2469 100644 --- a/plugin-taskbar/lxqttaskgroup.h +++ b/plugin-taskbar/lxqttaskgroup.h @@ -33,8 +33,7 @@ #include "../panel/ilxqtpanel.h" #include "../panel/ilxqtpanelplugin.h" -#include "lxqttaskbar.h" -#include "lxqtgrouppopup.h" + #include "lxqttaskbutton.h" #include From 2328de7af5de54176d8273b0eea90ae6777afa2f Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 11 Feb 2024 19:05:07 +0100 Subject: [PATCH 30/92] Port LXQtKbIndicatorPlugin to Qt6 --- plugin-kbindicator/kbindicator-plugin.cpp | 12 +++++++++--- plugin-kbindicator/src/kbdkeeper.cpp | 8 +++++--- plugin-kbindicator/src/x11/kbdlayout.cpp | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) 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/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; From b682f1e7fa9e7c3ae13198b9d88ef191db0955b2 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Wed, 28 Feb 2024 19:23:00 +0100 Subject: [PATCH 31/92] Replace QScopedPointer with std::unique_ptr - Use Xcb::ScopedCPointer for POD types --- panel/config/configpluginswidget.cpp | 14 +++++++------- panel/config/configpluginswidget.h | 2 +- panel/lxqtpanel.cpp | 12 ++++++------ panel/lxqtpanel.h | 4 ++-- panel/pluginsettings.h | 2 +- plugin-desktopswitch/desktopswitch.h | 4 ++-- plugin-kbindicator/src/kbdwatcher.cpp | 2 +- plugin-kbindicator/src/kbdwatcher.h | 2 +- plugin-kbindicator/src/x11/kbdlayout.h | 2 +- plugin-mainmenu/actionview.cpp | 4 ++-- plugin-tray/fdoselectionmanager.cpp | 8 ++++---- plugin-tray/sniproxy.cpp | 12 ++++++------ plugin-tray/xcbutils.h | 12 +++++++++--- plugin-volume/pulseaudioengine.cpp | 4 ++-- 14 files changed, 45 insertions(+), 39 deletions(-) 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/lxqtpanel.cpp b/panel/lxqtpanel.cpp index 127e2a8e4..86ba83141 100644 --- a/panel/lxqtpanel.cpp +++ b/panel/lxqtpanel.cpp @@ -221,8 +221,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(); @@ -446,11 +446,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) diff --git a/panel/lxqtpanel.h b/panel/lxqtpanel.h index f3be5cd96..7d847dfa6 100644 --- a/panel/lxqtpanel.h +++ b/panel/lxqtpanel.h @@ -470,12 +470,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/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-desktopswitch/desktopswitch.h b/plugin-desktopswitch/desktopswitch.h index c317ddbae..93a930dc2 100644 --- a/plugin-desktopswitch/desktopswitch.h +++ b/plugin-desktopswitch/desktopswitch.h @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include "desktopswitchbutton.h" @@ -85,7 +85,7 @@ class DesktopSwitch : public QObject, public ILXQtPanelPlugin LXQt::GridLayout *mLayout; int mRows; bool mShowOnlyActive; - QScopedPointer mDesktops; + std::unique_ptr mDesktops; DesktopSwitchButton::LabelType mLabelType; void refresh(); 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.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 804062af9..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); diff --git a/plugin-tray/fdoselectionmanager.cpp b/plugin-tray/fdoselectionmanager.cpp index 43d02646b..4afab6716 100644 --- a/plugin-tray/fdoselectionmanager.cpp +++ b/plugin-tray/fdoselectionmanager.cpp @@ -116,10 +116,10 @@ bool FdoSelectionManager::addDamageWatch(xcb_window_t client) 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(m_connection, 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. @@ -129,7 +129,7 @@ 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(m_connection, client, XCB_CW_EVENT_MASK, &events); - QScopedPointer changeAttrError(xcb_request_check(m_connection, changeAttrCookie)); + 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; diff --git a/plugin-tray/sniproxy.cpp b/plugin-tray/sniproxy.cpp index 2029ef580..e961613cc 100644 --- a/plugin-tray/sniproxy.cpp +++ b/plugin-tray/sniproxy.cpp @@ -218,7 +218,7 @@ 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(m_connection, m_windowId); - QScopedPointer windowAttributes(xcb_get_window_attributes_reply(m_connection, waCookie, nullptr)); + 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; } @@ -276,7 +276,7 @@ void SNIProxy::hideContainerWindow(xcb_window_t windowId) const QSize SNIProxy::calculateClientWindowSize() const { auto cookie = xcb_get_geometry(m_connection, m_windowId); - QScopedPointer clientGeom(xcb_get_geometry_reply(m_connection, cookie, nullptr)); + Xcb::ScopedCPointer clientGeom(xcb_get_geometry_reply(m_connection, cookie, nullptr)); QSize clientWindowSize; if (clientGeom) { @@ -429,8 +429,8 @@ QPoint SNIProxy::calculateClickPoint() const // 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(m_connection, m_windowId, XCB_SHAPE_SK_BOUNDING); - QScopedPointer extentsReply(xcb_shape_query_extents_reply(m_connection, extentsCookie, nullptr)); - QScopedPointer rectanglesReply(xcb_shape_get_rectangles_reply(m_connection, 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; @@ -553,14 +553,14 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) sendingClickEvent = true; auto cookieSize = xcb_get_geometry(m_connection, m_windowId); - QScopedPointer clientGeom(xcb_get_geometry_reply(m_connection, cookieSize, nullptr)); + Xcb::ScopedCPointer clientGeom(xcb_get_geometry_reply(m_connection, cookieSize, nullptr)); if (!clientGeom) { return; } auto cookie = xcb_query_pointer(m_connection, m_windowId); - QScopedPointer pointer(xcb_query_pointer_reply(m_connection, cookie, nullptr)); + 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;*/ diff --git a/plugin-tray/xcbutils.h b/plugin-tray/xcbutils.h index 5148f2283..d5a471e0e 100644 --- a/plugin-tray/xcbutils.h +++ b/plugin-tray/xcbutils.h @@ -35,7 +35,7 @@ #include #include -#include +#include #include /** XEMBED messages */ @@ -52,8 +52,14 @@ 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 { @@ -104,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; diff --git a/plugin-volume/pulseaudioengine.cpp b/plugin-volume/pulseaudioengine.cpp index 28cc7ff99..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(); } From 4343a79ba43b42bc08a8e99ec2e8aec7d939c8da Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Wed, 28 Feb 2024 19:35:55 +0100 Subject: [PATCH 32/92] Replace QVector with QList In Qt6 it's an alias --- panel/lxqtpanelapplication.cpp | 2 +- panel/lxqtpanellayout.cpp | 6 +++--- plugin-fancymenu/lxqtfancymenuappmap.cpp | 6 +++--- plugin-fancymenu/lxqtfancymenuappmap.h | 8 ++++---- plugin-fancymenu/lxqtfancymenuappmodel.cpp | 4 ++-- plugin-fancymenu/lxqtfancymenuappmodel.h | 4 ++-- plugin-taskbar/lxqttaskgroup.cpp | 2 +- plugin-tray/snidbus.h | 4 ++-- plugin-tray/xcbutils.h | 2 +- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/panel/lxqtpanelapplication.cpp b/panel/lxqtpanelapplication.cpp index 22cd97d81..430ea6f35 100644 --- a/panel/lxqtpanelapplication.cpp +++ b/panel/lxqtpanelapplication.cpp @@ -47,7 +47,7 @@ LXQtPanelApplicationPrivate::LXQtPanelApplicationPrivate(LXQtPanelApplication *q 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)) { diff --git a/panel/lxqtpanellayout.cpp b/panel/lxqtpanellayout.cpp index d304c8e23..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; @@ -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/plugin-fancymenu/lxqtfancymenuappmap.cpp b/plugin-fancymenu/lxqtfancymenuappmap.cpp index aaa392e2d..905b56295 100644 --- a/plugin-fancymenu/lxqtfancymenuappmap.cpp +++ b/plugin-fancymenu/lxqtfancymenuappmap.cpp @@ -230,10 +230,10 @@ 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 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-taskbar/lxqttaskgroup.cpp b/plugin-taskbar/lxqttaskgroup.cpp index 1af953ba7..4735764bd 100644 --- a/plugin-taskbar/lxqttaskgroup.cpp +++ b/plugin-taskbar/lxqttaskgroup.cpp @@ -620,7 +620,7 @@ void LXQtTaskGroup::wheelEvent(QWheelEvent* event) bool LXQtTaskGroup::onWindowChanged(WId window, NET::Properties prop, NET::Properties2 prop2) { // returns true if the class is preserved bool needsRefreshVisibility{false}; - QVector buttons; + QList buttons; if (mButtonHash.contains(window)) buttons.append(mButtonHash.value(window)); 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/xcbutils.h b/plugin-tray/xcbutils.h index d5a471e0e..497aa8c84 100644 --- a/plugin-tray/xcbutils.h +++ b/plugin-tray/xcbutils.h @@ -36,7 +36,7 @@ #include #include -#include +#include /** XEMBED messages */ #define XEMBED_EMBEDDED_NOTIFY 0 From 633b8a10a5b5cc32e2f5150bff49907587e61fb6 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 11 Feb 2024 19:16:25 +0100 Subject: [PATCH 33/92] SNIProxy: use QBitmap::fromImage TODO TODO: is behavior equivalent? Conversion flags... --- plugin-tray/sniproxy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-tray/sniproxy.cpp b/plugin-tray/sniproxy.cpp index e961613cc..5122b0d38 100644 --- a/plugin-tray/sniproxy.cpp +++ b/plugin-tray/sniproxy.cpp @@ -400,7 +400,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(); From f0835c4c9b7ecaa2e1c3f1df7b8b90eaba484398 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Wed, 28 Feb 2024 19:48:33 +0100 Subject: [PATCH 34/92] README: update mentioned dependencies --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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. From 4bdb2434963e97c6e7d963a88c3bd475cd0ec595 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 28 Jan 2024 14:48:18 +0100 Subject: [PATCH 35/92] TaskBar: forward declare --- plugin-taskbar/lxqttaskbar.cpp | 12 ++++++++++-- plugin-taskbar/lxqttaskbar.h | 18 +++++++++++------- plugin-taskbar/lxqttaskbarconfiguration.h | 4 ++-- plugin-taskbar/lxqttaskbarplugin.cpp | 10 +++++++++- plugin-taskbar/lxqttaskbarplugin.h | 10 ++++------ plugin-taskbar/lxqttaskbutton.cpp | 8 ++++---- plugin-taskbar/lxqttaskbutton.h | 2 +- plugin-taskbar/lxqttaskgroup.cpp | 2 ++ plugin-taskbar/lxqttaskgroup.h | 6 ++---- 9 files changed, 45 insertions(+), 27 deletions(-) diff --git a/plugin-taskbar/lxqttaskbar.cpp b/plugin-taskbar/lxqttaskbar.cpp index 5dfa289c9..c4fa01da2 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 @@ -39,11 +41,12 @@ #include #include +#include "ilxqtpanelplugin.h" +#include "pluginsettings.h" + #include #include -#include -#include "lxqttaskbar.h" #include "lxqttaskgroup.h" #include "../panel/pluginsettings.h" @@ -591,6 +594,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 03e2bd0d2..d80d1ea13 100644 --- a/plugin-taskbar/lxqttaskbar.h +++ b/plugin-taskbar/lxqttaskbar.h @@ -32,30 +32,33 @@ #ifndef LXQTTASKBAR_H #define LXQTTASKBAR_H -#include "../panel/ilxqtpanel.h" -#include "../panel/ilxqtpanelplugin.h" - #include #include #include -#include + #include "../panel/ilxqtpanel.h" #include #include #include +class ILXQtPanel; +class ILXQtPanelPlugin; + class QSignalMapper; -class LXQtTaskButton; class LXQtTaskGroup; -class ElidedButtonStyle; class LeftAlignedTextStyle; namespace LXQt { class GridLayout; } +namespace GlobalKeyShortcut +{ +class Action; +} + class LXQtTaskBar : public QFrame { Q_OBJECT @@ -80,7 +83,8 @@ 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; } public slots: 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 ae8af1403..759e6db46 100644 --- a/plugin-taskbar/lxqttaskbarplugin.cpp +++ b/plugin-taskbar/lxqttaskbarplugin.cpp @@ -28,6 +28,8 @@ #include "lxqttaskbarplugin.h" +#include "lxqttaskbar.h" + #include "lxqttaskbarconfiguration.h" LXQtTaskBarPlugin::LXQtTaskBarPlugin(const ILXQtPanelPluginStartupInfo &startupInfo): @@ -36,7 +38,6 @@ LXQtTaskBarPlugin::LXQtTaskBarPlugin(const ILXQtPanelPluginStartupInfo &startupI { mTaskBar = new LXQtTaskBar(this); - } @@ -45,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/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index 3bcc7ee5b..b8ec92b72 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -31,6 +31,8 @@ #include "lxqttaskgroup.h" #include "lxqttaskbar.h" +#include "ilxqtpanelplugin.h" + #include #include @@ -49,11 +51,8 @@ #include #include -#include "lxqttaskbutton.h" -#include "lxqttaskgroup.h" -#include "lxqttaskbar.h" - #include + // Necessary for closeApplication() #include @@ -61,6 +60,7 @@ #include #undef Bool + bool LXQtTaskButton::sDraggging = false; /************************************************ diff --git a/plugin-taskbar/lxqttaskbutton.h b/plugin-taskbar/lxqttaskbutton.h index 69f3b41d8..73d0886d4 100644 --- a/plugin-taskbar/lxqttaskbutton.h +++ b/plugin-taskbar/lxqttaskbutton.h @@ -33,12 +33,12 @@ #include #include + #include "../panel/ilxqtpanel.h" class QPainter; class QPalette; class QMimeData; -class LXQtTaskGroup; class LXQtTaskBar; class LeftAlignedTextStyle : public QProxyStyle diff --git a/plugin-taskbar/lxqttaskgroup.cpp b/plugin-taskbar/lxqttaskgroup.cpp index 4735764bd..b7596881b 100644 --- a/plugin-taskbar/lxqttaskgroup.cpp +++ b/plugin-taskbar/lxqttaskgroup.cpp @@ -32,6 +32,8 @@ #include "lxqttaskbar.h" #include "lxqtgrouppopup.h" +#include "ilxqtpanelplugin.h" + #include #include #include diff --git a/plugin-taskbar/lxqttaskgroup.h b/plugin-taskbar/lxqttaskgroup.h index f1e7e2469..3787f411f 100644 --- a/plugin-taskbar/lxqttaskgroup.h +++ b/plugin-taskbar/lxqttaskgroup.h @@ -31,11 +31,9 @@ #ifndef LXQTTASKGROUP_H #define LXQTTASKGROUP_H -#include "../panel/ilxqtpanel.h" -#include "../panel/ilxqtpanelplugin.h" - #include "lxqttaskbutton.h" -#include + +#include class QVBoxLayout; class ILXQtPanelPlugin; From 1d5f0f8cb51b6a57a75c23cdde11a29698a43079 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 27 Jan 2024 18:37:31 +0100 Subject: [PATCH 36/92] TaskBar: new ILXQtTaskbarAbstractBackend This is an abstract interface to operate windows and workspaces --- plugin-taskbar/CMakeLists.txt | 5 + .../ilxqttaskbarabstractbackend.cpp | 25 +++++ plugin-taskbar/ilxqttaskbarabstractbackend.h | 94 +++++++++++++++++++ plugin-taskbar/lxqttaskbartypes.h | 32 +++++++ 4 files changed, 156 insertions(+) create mode 100644 plugin-taskbar/ilxqttaskbarabstractbackend.cpp create mode 100644 plugin-taskbar/ilxqttaskbarabstractbackend.h create mode 100644 plugin-taskbar/lxqttaskbartypes.h diff --git a/plugin-taskbar/CMakeLists.txt b/plugin-taskbar/CMakeLists.txt index 1d627f23e..9ca6321cc 100644 --- a/plugin-taskbar/CMakeLists.txt +++ b/plugin-taskbar/CMakeLists.txt @@ -7,6 +7,9 @@ set(HEADERS lxqttaskbarplugin.h lxqttaskgroup.h lxqtgrouppopup.h + + ilxqttaskbarabstractbackend.h + lxqttaskbartypes.h ) set(SOURCES @@ -16,6 +19,8 @@ set(SOURCES lxqttaskbarplugin.cpp lxqttaskgroup.cpp lxqtgrouppopup.cpp + + ilxqttaskbarabstractbackend.cpp ) set(UIS diff --git a/plugin-taskbar/ilxqttaskbarabstractbackend.cpp b/plugin-taskbar/ilxqttaskbarabstractbackend.cpp new file mode 100644 index 000000000..d0959fb78 --- /dev/null +++ b/plugin-taskbar/ilxqttaskbarabstractbackend.cpp @@ -0,0 +1,25 @@ +#include "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; //TODO: are X11 desktops 1 based? + else if (targetWorkspace < 1) + targetWorkspace = count; + + setWindowOnWorkspace(windowId, targetWorkspace); +} diff --git a/plugin-taskbar/ilxqttaskbarabstractbackend.h b/plugin-taskbar/ilxqttaskbarabstractbackend.h new file mode 100644 index 000000000..f37a4081b --- /dev/null +++ b/plugin-taskbar/ilxqttaskbarabstractbackend.h @@ -0,0 +1,94 @@ +#ifndef ILXQTTASKBARABSTRACTBACKEND_H +#define ILXQTTASKBARABSTRACTBACKEND_H + +#include + +#include "lxqttaskbartypes.h" + +class QIcon; +class QScreen; + +//FIXME: add something like bool KWindowInfo::actionSupported(...) + +class ILXQtTaskbarAbstractBackend : public QObject +{ + Q_OBJECT + +public: + enum class WindowProperty + { + Title = 0, + Icon, + State, + Urgency, + WindowClass, + Workspace + }; + + explicit ILXQtTaskbarAbstractBackend(QObject *parent = nullptr); + + // 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 + 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; + +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/plugin-taskbar/lxqttaskbartypes.h b/plugin-taskbar/lxqttaskbartypes.h new file mode 100644 index 000000000..d841fec74 --- /dev/null +++ b/plugin-taskbar/lxqttaskbartypes.h @@ -0,0 +1,32 @@ +#ifndef LXQTTASKBARTYPES_H +#define LXQTTASKBARTYPES_H + +#include + +typedef quintptr WId; + +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 From 3f913a2f5ee000c61195f40fd78cee55368919ca Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 28 Jan 2024 16:37:03 +0100 Subject: [PATCH 37/92] ILXQtTaskbarAbstractBackend: add supportsAction() method - Move WindowProperty enum to lxqttaskbartypes.h --- plugin-taskbar/ilxqttaskbarabstractbackend.h | 15 +++---------- plugin-taskbar/lxqttaskbartypes.h | 22 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/plugin-taskbar/ilxqttaskbarabstractbackend.h b/plugin-taskbar/ilxqttaskbarabstractbackend.h index f37a4081b..932d64fc0 100644 --- a/plugin-taskbar/ilxqttaskbarabstractbackend.h +++ b/plugin-taskbar/ilxqttaskbarabstractbackend.h @@ -8,25 +8,16 @@ class QIcon; class QScreen; -//FIXME: add something like bool KWindowInfo::actionSupported(...) - class ILXQtTaskbarAbstractBackend : public QObject { Q_OBJECT public: - enum class WindowProperty - { - Title = 0, - Icon, - State, - Urgency, - WindowClass, - Workspace - }; - explicit ILXQtTaskbarAbstractBackend(QObject *parent = nullptr); + // Backend + virtual bool supportsAction(WId windowId, LXQtTaskBarBackendAction action) const = 0; + // Windows virtual bool reloadWindows() = 0; diff --git a/plugin-taskbar/lxqttaskbartypes.h b/plugin-taskbar/lxqttaskbartypes.h index d841fec74..ccea42027 100644 --- a/plugin-taskbar/lxqttaskbartypes.h +++ b/plugin-taskbar/lxqttaskbartypes.h @@ -5,6 +5,28 @@ typedef quintptr WId; +enum class LXQtTaskBarBackendAction +{ + Move = 0, + Resize, + Maximize, + MaximizeVertically, + MaximizeHorizontally, + Minimize, + RollUp, + FullScreen +}; + +enum class LXQtTaskBarWindowProperty +{ + Title = 0, + Icon, + State, + Urgency, + WindowClass, + Workspace +}; + enum class LXQtTaskBarWindowState { Hidden = 0, From cd1f762c5efbaa7ad0a5ed3e6952f50135da4942 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 27 Jan 2024 18:39:44 +0100 Subject: [PATCH 38/92] TaskBar: add X11 backend --- plugin-taskbar/CMakeLists.txt | 2 + plugin-taskbar/lxqttaskbarbackend_x11.cpp | 582 ++++++++++++++++++++++ plugin-taskbar/lxqttaskbarbackend_x11.h | 80 +++ 3 files changed, 664 insertions(+) create mode 100644 plugin-taskbar/lxqttaskbarbackend_x11.cpp create mode 100644 plugin-taskbar/lxqttaskbarbackend_x11.h diff --git a/plugin-taskbar/CMakeLists.txt b/plugin-taskbar/CMakeLists.txt index 9ca6321cc..053381bef 100644 --- a/plugin-taskbar/CMakeLists.txt +++ b/plugin-taskbar/CMakeLists.txt @@ -10,6 +10,7 @@ set(HEADERS ilxqttaskbarabstractbackend.h lxqttaskbartypes.h + lxqttaskbarbackend_x11.h ) set(SOURCES @@ -21,6 +22,7 @@ set(SOURCES lxqtgrouppopup.cpp ilxqttaskbarabstractbackend.cpp + lxqttaskbarbackend_x11.cpp ) set(UIS diff --git a/plugin-taskbar/lxqttaskbarbackend_x11.cpp b/plugin-taskbar/lxqttaskbarbackend_x11.cpp new file mode 100644 index 000000000..cc7759f4e --- /dev/null +++ b/plugin-taskbar/lxqttaskbarbackend_x11.cpp @@ -0,0 +1,582 @@ +#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 (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); +} diff --git a/plugin-taskbar/lxqttaskbarbackend_x11.h b/plugin-taskbar/lxqttaskbarbackend_x11.h new file mode 100644 index 000000000..26c721cf7 --- /dev/null +++ b/plugin-taskbar/lxqttaskbarbackend_x11.h @@ -0,0 +1,80 @@ +#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; + +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 From 740639e321efcbed825f75f029a77c6025bfd6ed Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 27 Jan 2024 18:41:42 +0100 Subject: [PATCH 39/92] TaskBar: new LXQtTaskBarProxyModel This model will manage the tasks shown --- plugin-taskbar/CMakeLists.txt | 2 + plugin-taskbar/lxqttaskbarproxymodel.cpp | 257 +++++++++++++++++++++++ plugin-taskbar/lxqttaskbarproxymodel.h | 100 +++++++++ 3 files changed, 359 insertions(+) create mode 100644 plugin-taskbar/lxqttaskbarproxymodel.cpp create mode 100644 plugin-taskbar/lxqttaskbarproxymodel.h diff --git a/plugin-taskbar/CMakeLists.txt b/plugin-taskbar/CMakeLists.txt index 053381bef..be434f6a6 100644 --- a/plugin-taskbar/CMakeLists.txt +++ b/plugin-taskbar/CMakeLists.txt @@ -11,6 +11,7 @@ set(HEADERS ilxqttaskbarabstractbackend.h lxqttaskbartypes.h lxqttaskbarbackend_x11.h + lxqttaskbarproxymodel.h ) set(SOURCES @@ -23,6 +24,7 @@ set(SOURCES ilxqttaskbarabstractbackend.cpp lxqttaskbarbackend_x11.cpp + lxqttaskbarproxymodel.cpp ) set(UIS diff --git a/plugin-taskbar/lxqttaskbarproxymodel.cpp b/plugin-taskbar/lxqttaskbarproxymodel.cpp new file mode 100644 index 000000000..e2f1d3941 --- /dev/null +++ b/plugin-taskbar/lxqttaskbarproxymodel.cpp @@ -0,0 +1,257 @@ +#include "lxqttaskbarproxymodel.h" + +#include "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..be5799076 --- /dev/null +++ b/plugin-taskbar/lxqttaskbarproxymodel.h @@ -0,0 +1,100 @@ +#ifndef LXQTTASKBARPROXYMODEL_H +#define LXQTTASKBARPROXYMODEL_H + +#include +#include + +#include "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 From 47bba93faddca4e64c3cf74ae345f3426b50ab69 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 27 Jan 2024 19:00:46 +0100 Subject: [PATCH 40/92] TaskBar: use backend in LXQtTaskBar --- plugin-taskbar/lxqttaskbar.cpp | 14 +++++++++++--- plugin-taskbar/lxqttaskbar.h | 6 ++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/plugin-taskbar/lxqttaskbar.cpp b/plugin-taskbar/lxqttaskbar.cpp index c4fa01da2..fc60496a3 100644 --- a/plugin-taskbar/lxqttaskbar.cpp +++ b/plugin-taskbar/lxqttaskbar.cpp @@ -54,6 +54,8 @@ #include #undef Bool +#include "lxqttaskbarbackend_x11.h" + using namespace LXQt; /************************************************ @@ -80,7 +82,8 @@ 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); @@ -94,6 +97,10 @@ LXQtTaskBar::LXQtTaskBar(ILXQtPanelPlugin *plugin, QWidget *parent) : mPlaceHolder->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); mLayout->addWidget(mPlaceHolder); + // Create model + //TODO: use backend factory + mBackend = new LXQtTaskbarX11Backend(this); + QTimer::singleShot(0, this, &LXQtTaskBar::settingsChanged); setAcceptDrops(true); @@ -282,7 +289,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); @@ -534,7 +541,8 @@ void LXQtTaskBar::settingsChanged() if (iconByClassOld != mIconByClass) emit iconByClassChanged(); - refreshTaskList(); + refreshTaskList(); //TODO: remove + mBackend->reloadWindows(); } /************************************************ diff --git a/plugin-taskbar/lxqttaskbar.h b/plugin-taskbar/lxqttaskbar.h index d80d1ea13..c36bca7e0 100644 --- a/plugin-taskbar/lxqttaskbar.h +++ b/plugin-taskbar/lxqttaskbar.h @@ -50,6 +50,8 @@ class LXQtTaskGroup; class LeftAlignedTextStyle; +class ILXQtTaskbarAbstractBackend; + namespace LXQt { class GridLayout; } @@ -87,6 +89,8 @@ class LXQtTaskBar : public QFrame ILXQtPanel * panel() const; inline ILXQtPanelPlugin * plugin() const { return mPlugin; } + inline ILXQtTaskbarAbstractBackend *getBackend() const { return mBackend; } + public slots: void settingsChanged(); @@ -156,6 +160,8 @@ private slots: ILXQtPanelPlugin *mPlugin; QWidget *mPlaceHolder; LeftAlignedTextStyle *mStyle; + + ILXQtTaskbarAbstractBackend *mBackend; }; #endif // LXQTTASKBAR_H From 43761a9f212ef5cc24c85cc91bdeec2b8319f537 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 3 Feb 2024 16:30:07 +0100 Subject: [PATCH 41/92] TaskBar: initial use of backend in LXQtTaskButton --- plugin-taskbar/lxqttaskbutton.cpp | 169 +++--------------------------- plugin-taskbar/lxqttaskbutton.h | 7 +- plugin-taskbar/lxqttaskgroup.cpp | 28 ++--- 3 files changed, 35 insertions(+), 169 deletions(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index b8ec92b72..d97d2f426 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -51,6 +51,7 @@ #include #include +//TODO: remove #include // Necessary for closeApplication() @@ -61,6 +62,8 @@ #undef Bool +#include "ilxqttaskbarabstractbackend.h" + bool LXQtTaskButton::sDraggging = false; /************************************************ @@ -84,6 +87,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), @@ -144,8 +148,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); } @@ -168,57 +171,6 @@ void LXQtTaskButton::updateIcon() 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. - - WId appRootWindow = 0; - xcb_connection_t* x11conn = nullptr; - - auto *x11Application = qGuiApp->nativeInterface(); - if(x11Application) - { - appRootWindow = XDefaultRootWindow(x11Application->display()); - x11conn = x11Application->connection(); - } - else - { - //qWarning() << "LXQtTaskBar: not implemented on Wayland"; - return; - } - - - if (!x11conn) { - return; - } - - NETWinInfo info(x11conn, - 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); -} - /************************************************ ************************************************/ @@ -433,8 +385,7 @@ void LXQtTaskButton::mouseMoveEvent(QMouseEvent* event) ************************************************/ bool LXQtTaskButton::isApplicationHidden() const { - KWindowInfo info(mWindow, NET::WMState); - return (info.state() & NET::Hidden); + return false; //FIXME: unused } /************************************************ @@ -442,7 +393,7 @@ bool LXQtTaskButton::isApplicationHidden() const ************************************************/ bool LXQtTaskButton::isApplicationActive() const { - return KX11Extras::activeWindow() == mWindow; + return mBackend->isWindowActive(mWindow); } /************************************************ @@ -587,12 +538,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); } /************************************************ @@ -600,17 +551,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); } /************************************************ @@ -618,53 +559,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); - KX11Extras::clearState(mWindow, NET::MaxHoriz | NET::MaxVert | NET::Max | NET::FullScreen); - - - auto *x11Application = qGuiApp->nativeInterface(); - if(x11Application) - { - NETRootInfo(x11Application->connection(), NET::Properties(), NET::WM2MoveResizeWindow).moveResizeWindowRequest(mWindow, flags, X, Y, 0, 0); - } - else - { - //qWarning() << "LXQtTaskBar: not implemented on Wayland"; - } - - QTimer::singleShot(200, this, [this, state] - { - KX11Extras::setState(mWindow, state); - raiseApplication(); - }); - break; - } - } - } + mBackend->moveApplicationToPrevNextMonitor(mWindow, next, parentTaskBar()->raiseOnCurrentDesktop()); } /************************************************ @@ -672,26 +567,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); - - auto *x11Application = qGuiApp->nativeInterface(); - if(x11Application) - { - NETRootInfo(x11Application->connection(), NET::WMMoveResize).moveResizeRequest(mWindow, X, Y, NET::Move); - } - else - { - //qWarning() << "LXQtTaskBar: not implemented on Wayland"; - } + mBackend->moveApplication(mWindow); } /************************************************ @@ -699,26 +575,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); - - auto *x11Application = qGuiApp->nativeInterface(); - if(x11Application) - { - NETRootInfo(x11Application->connection(), NET::WMMoveResize).moveResizeRequest(mWindow, X, Y, NET::BottomRight); - } - else - { - //qWarning() << "LXQtTaskBar: not implemented on Wayland"; - } + mBackend->resizeApplication(mWindow); } /************************************************ diff --git a/plugin-taskbar/lxqttaskbutton.h b/plugin-taskbar/lxqttaskbutton.h index 73d0886d4..9ccca36fa 100644 --- a/plugin-taskbar/lxqttaskbutton.h +++ b/plugin-taskbar/lxqttaskbutton.h @@ -41,6 +41,8 @@ class QPalette; class QMimeData; 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 b7596881b..39a8e779b 100644 --- a/plugin-taskbar/lxqttaskgroup.cpp +++ b/plugin-taskbar/lxqttaskgroup.cpp @@ -43,9 +43,13 @@ #include #include +//TODO: remove #include //For nativeInterface() #include #include +#undef Bool + +#include "ilxqttaskbarabstractbackend.h" /************************************************ @@ -62,14 +66,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); } /************************************************ @@ -102,7 +106,7 @@ void LXQtTaskGroup::contextMenuEvent(QContextMenuEvent *event) void LXQtTaskGroup::closeGroup() { for (LXQtTaskButton *button : std::as_const(mButtonHash) ) - if (button->isOnDesktop(KX11Extras::currentDesktop())) + if (button->isOnDesktop(mBackend->getCurrentWorkspace())) button->closeApplication(); } @@ -310,7 +314,7 @@ void LXQtTaskGroup::onClicked(bool) { if (visibleButtonsCount() > 1) { - setChecked(mButtonHash.contains(KX11Extras::activeWindow())); + setChecked(mButtonHash.contains(mBackend->getActiveWindow())); setPopupVisible(true); } } @@ -449,13 +453,13 @@ void LXQtTaskGroup::refreshIconsGeometry() if (mSingleButton) { - refreshIconGeometry(rect); + mBackend->refreshIconGeometry(windowId(), rect); return; } for(LXQtTaskButton *but : std::as_const(mButtonHash)) { - but->refreshIconGeometry(rect); + mBackend->refreshIconGeometry(but->windowId(), rect); but->setIconSize(QSize(plugin()->panel()->iconSize(), plugin()->panel()->iconSize())); } } From 8dbc2e5925d8a6a19263fed54defc3260775dcef Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 3 Feb 2024 16:34:11 +0100 Subject: [PATCH 42/92] TaskBar: use backend for urgency hint --- plugin-taskbar/lxqttaskbutton.cpp | 14 +------------- plugin-taskbar/lxqttaskgroup.cpp | 12 +++++------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index d97d2f426..3bd55cdbe 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -28,7 +28,6 @@ * END_COMMON_COPYRIGHT_HEADER */ #include "lxqttaskbutton.h" -#include "lxqttaskgroup.h" #include "lxqttaskbar.h" #include "ilxqtpanelplugin.h" @@ -121,18 +120,7 @@ LXQtTaskButton::LXQtTaskButton(const WId window, LXQtTaskBar * taskbar, QWidget mWheelDelta = 0; // forget previous wheel deltas }); - auto *x11Application = qGuiApp->nativeInterface(); - if(x11Application) - { - WId appRootWindow = XDefaultRootWindow(x11Application->display()); - setUrgencyHint(NETWinInfo(x11Application->connection(), mWindow, appRootWindow, NET::Properties{}, NET::WM2Urgency).urgency() - || KWindowInfo{mWindow, NET::WMState}.hasState(NET::DemandsAttention)); - } - else - { - qWarning() << "LXQtTaskBar: not implemented on Wayland"; - } - + setUrgencyHint(mBackend->applicationDemandsAttention(mWindow)); connect(LXQt::Settings::globalSettings(), &LXQt::GlobalSettings::iconThemeChanged, this, &LXQtTaskButton::updateIcon); connect(mParentTaskBar, &LXQtTaskBar::iconByClassChanged, this, &LXQtTaskButton::updateIcon); diff --git a/plugin-taskbar/lxqttaskgroup.cpp b/plugin-taskbar/lxqttaskgroup.cpp index 39a8e779b..4ad7f5299 100644 --- a/plugin-taskbar/lxqttaskgroup.cpp +++ b/plugin-taskbar/lxqttaskgroup.cpp @@ -45,7 +45,6 @@ //TODO: remove #include //For nativeInterface() -#include #include #undef Bool @@ -676,6 +675,8 @@ bool LXQtTaskGroup::onWindowChanged(WId window, NET::Properties prop, NET::Prope if (prop2.testFlag(NET::WM2Urgency)) { set_urgency = true; + //FIXME: original code here did not consider "demand attention", was it intentional? + urgency = mBackend->applicationDemandsAttention(window); } if (prop.testFlag(NET::WMState)) { @@ -683,12 +684,9 @@ bool LXQtTaskGroup::onWindowChanged(WId window, NET::Properties prop, NET::Prope // Force refresh urgency if (!set_urgency) - { - //TODO: maybe do it in common place with NET::WM2Urgency - std::for_each(buttons.begin(), buttons.end(), std::bind(&LXQtTaskButton::setUrgencyHint, std::placeholders::_1, urgency || info.hasState(NET::DemandsAttention))); - set_urgency = false; - } - + 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); From 1ac62fb4b9e42452f322c367a74b3917d97d7c5c Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 3 Feb 2024 16:36:29 +0100 Subject: [PATCH 43/92] TaskBar: use backend to set window layer --- plugin-taskbar/lxqttaskbutton.cpp | 37 +++++++++---------------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index 3bd55cdbe..14f30d957 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -497,23 +497,7 @@ void LXQtTaskButton::setApplicationLayer() return; int layer = act->data().toInt(); - switch(layer) - { - case NET::KeepAbove: - KX11Extras::clearState(mWindow, NET::KeepBelow); - KX11Extras::setState(mWindow, NET::KeepAbove); - break; - - case NET::KeepBelow: - KX11Extras::clearState(mWindow, NET::KeepAbove); - KX11Extras::setState(mWindow, NET::KeepBelow); - break; - - default: - KX11Extras::clearState(mWindow, NET::KeepBelow); - KX11Extras::clearState(mWindow, NET::KeepAbove); - break; - } + mBackend->setWindowLayer(mWindow, LXQtTaskBarWindowLayer(layer)); } /************************************************ @@ -706,22 +690,23 @@ void LXQtTaskButton::contextMenuEvent(QContextMenuEvent* event) QMenu* layerMenu = menu->addMenu(tr("&Layer")); - a = layerMenu->addAction(tr("Always on &top")); + LXQtTaskBarWindowLayer currentLayer = mBackend->getWindowLayer(mWindow); + // FIXME: There is no info.actionSupported(NET::ActionKeepAbove) - a->setEnabled(!(state & NET::KeepAbove)); - a->setData(NET::KeepAbove); + a = layerMenu->addAction(tr("Always on &top")); + 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 = layerMenu->addAction(tr("Always on &bottom")); + a->setEnabled(currentLayer != LXQtTaskBarWindowLayer::KeepBelow); + a->setData(int(LXQtTaskBarWindowLayer::KeepBelow)); connect(a, &QAction::triggered, this, &LXQtTaskButton::setApplicationLayer); /********** Kill menu **********/ From 24113953cd70223fa61ffe7141aef1aef3f7a84f Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 3 Feb 2024 16:53:02 +0100 Subject: [PATCH 44/92] TaskBar: use backend to close and raise window Also use it to get window icon --- plugin-taskbar/lxqttaskbutton.cpp | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index 14f30d957..ab6924cd6 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -154,7 +154,7 @@ void LXQtTaskButton::updateIcon() if (ico.isNull()) { int devicePixels = mIconSize * devicePixelRatioF(); - ico = KX11Extras::icon(mWindow, devicePixels, devicePixels); + ico = mBackend->getApplicationIcon(mWindow, devicePixels); } setIcon(ico.isNull() ? XdgIcon::defaultApplicationIcon() : ico); } @@ -389,21 +389,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()); } /************************************************ @@ -475,16 +461,7 @@ void LXQtTaskButton::unShadeApplication() ************************************************/ void LXQtTaskButton::closeApplication() { - auto *x11Application = qGuiApp->nativeInterface(); - if(x11Application) - { - // FIXME: Why there is no such thing in KX11Extras?? - NETRootInfo(x11Application->connection(), NET::CloseWindow).closeWindowRequest(mWindow); - } - else - { - qWarning() << "LXQtTaskBar: not implemented on Wayland"; - } + mBackend->closeWindow(mWindow); } /************************************************ From 6b3b0ddb072afb2b1d4d7e4ec548b20c2d79e64e Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 3 Feb 2024 17:00:58 +0100 Subject: [PATCH 45/92] TaskBar: use backend to roll up (shade) windows --- plugin-taskbar/lxqttaskbutton.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index ab6924cd6..7c3508bff 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -445,7 +445,7 @@ void LXQtTaskButton::deMaximizeApplication() ************************************************/ void LXQtTaskButton::shadeApplication() { - KX11Extras::setState(mWindow, NET::Shaded); + mBackend->setWindowState(mWindow, LXQtTaskBarWindowState::RolledUp, true); } /************************************************ @@ -453,7 +453,7 @@ void LXQtTaskButton::shadeApplication() ************************************************/ void LXQtTaskButton::unShadeApplication() { - KX11Extras::clearState(mWindow, NET::Shaded); + mBackend->setWindowState(mWindow, LXQtTaskBarWindowState::RolledUp, false); } /************************************************ From 5462b2fa45f235f7a534bde62b3add2a64092a60 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 3 Feb 2024 17:09:37 +0100 Subject: [PATCH 46/92] TaskBar: use backend to minimize window --- plugin-taskbar/lxqttaskbutton.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index 7c3508bff..c6e173a1d 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -397,7 +397,7 @@ void LXQtTaskButton::raiseApplication() ************************************************/ void LXQtTaskButton::minimizeApplication() { - KX11Extras::minimizeWindow(mWindow); + mBackend->setWindowState(mWindow, LXQtTaskBarWindowState::Minimized, true); } /************************************************ From e7c5a98e04c49a535c7c0239f3242e5cebdc35bd Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 3 Feb 2024 17:10:08 +0100 Subject: [PATCH 47/92] TaskBar: use backend to de-maximize window --- plugin-taskbar/lxqttaskbutton.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index c6e173a1d..77d7408c4 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -434,10 +434,10 @@ void LXQtTaskButton::maximizeApplication() ************************************************/ void LXQtTaskButton::deMaximizeApplication() { - KX11Extras::clearState(mWindow, NET::Max); + mBackend->setWindowState(mWindow, LXQtTaskBarWindowState::Maximized, false); - if (!isApplicationActive()) - raiseApplication(); + if(!mBackend->isWindowActive(mWindow)) + mBackend->raiseWindow(mWindow, parentTaskBar()->raiseOnCurrentDesktop()); } /************************************************ From 8297648f62ddf2fe8d3322cdb432c53be596116a Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 3 Feb 2024 17:58:59 +0100 Subject: [PATCH 48/92] TaskBar: use backend to get window state --- plugin-taskbar/lxqttaskbutton.cpp | 35 +++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index 77d7408c4..b9a734b69 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -539,7 +539,7 @@ void LXQtTaskButton::contextMenuEvent(QContextMenuEvent* event) } KWindowInfo info(mWindow, NET::Properties(), NET::WM2AllowedActions); - unsigned long state = KWindowInfo(mWindow, NET::WMState).state(); + NET::States state = KWindowInfo(mWindow, NET::WMState).state(); QMenu * menu = new QMenu(tr("Application")); menu->setAttribute(Qt::WA_DeleteOnClose); @@ -623,42 +623,59 @@ void LXQtTaskButton::contextMenuEvent(QContextMenuEvent* event) /********** State menu **********/ menu->addSeparator(); + LXQtTaskBarWindowState windowState = mBackend->getWindowState(mWindow); + a = menu->addAction(tr("Ma&ximize")); - a->setEnabled(info.actionSupported(NET::ActionMax) && (!(state & NET::Max) || (state & NET::Hidden))); + a->setEnabled(info.actionSupported(NET::ActionMax) + && windowState != LXQtTaskBarWindowState::Maximized + && windowState != LXQtTaskBarWindowState::Hidden); a->setData(NET::Max); 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->setEnabled(info.actionSupported(NET::ActionMaxVert) + && windowState != LXQtTaskBarWindowState::MaximizedVertically + && windowState != LXQtTaskBarWindowState::Hidden); a->setData(NET::MaxVert); 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->setEnabled(info.actionSupported(NET::ActionMaxHoriz) + && windowState != LXQtTaskBarWindowState::MaximizedHorizontally + && windowState != LXQtTaskBarWindowState::Hidden); a->setData(NET::MaxHoriz); 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(windowState == LXQtTaskBarWindowState::Hidden + || windowState == LXQtTaskBarWindowState::Minimized + || windowState == LXQtTaskBarWindowState::Maximized + || windowState == LXQtTaskBarWindowState::MaximizedVertically + || windowState == 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(info.actionSupported(NET::ActionMinimize) + && windowState != LXQtTaskBarWindowState::Hidden + && windowState != LXQtTaskBarWindowState::Minimized); connect(a, &QAction::triggered, this, &LXQtTaskButton::minimizeApplication); - if (state & NET::Shaded) + if (windowState == LXQtTaskBarWindowState::RolledUp) { a = menu->addAction(tr("Roll down")); - a->setEnabled(info.actionSupported(NET::ActionShade) && !(state & NET::Hidden)); + a->setEnabled(info.actionSupported(NET::ActionShade) + && windowState != LXQtTaskBarWindowState::Hidden + && windowState != 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(info.actionSupported(NET::ActionShade) + && windowState != LXQtTaskBarWindowState::Hidden); connect(a, &QAction::triggered, this, &LXQtTaskButton::shadeApplication); } From 8434907affb77b8751ecb6019b0ada582c2a83ef Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 3 Feb 2024 18:26:53 +0100 Subject: [PATCH 49/92] TaskBar: use backend to set window state --- plugin-taskbar/lxqttaskbutton.cpp | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index b9a734b69..4954d6adb 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -410,23 +410,10 @@ void LXQtTaskButton::maximizeApplication() return; int state = act->data().toInt(); - switch (state) - { - case NET::MaxHoriz: - KX11Extras::setState(mWindow, NET::MaxHoriz); - break; + mBackend->setWindowState(mWindow, LXQtTaskBarWindowState(state), true); - case NET::MaxVert: - KX11Extras::setState(mWindow, NET::MaxVert); - break; - - default: - KX11Extras::setState(mWindow, NET::Max); - break; - } - - if (!isApplicationActive()) - raiseApplication(); + if(!mBackend->isWindowActive(mWindow)) + mBackend->raiseWindow(mWindow, parentTaskBar()->raiseOnCurrentDesktop()); } /************************************************ @@ -629,7 +616,7 @@ void LXQtTaskButton::contextMenuEvent(QContextMenuEvent* event) a->setEnabled(info.actionSupported(NET::ActionMax) && windowState != LXQtTaskBarWindowState::Maximized && windowState != LXQtTaskBarWindowState::Hidden); - a->setData(NET::Max); + a->setData(int(LXQtTaskBarWindowState::Maximized)); connect(a, &QAction::triggered, this, &LXQtTaskButton::maximizeApplication); if (event->modifiers() & Qt::ShiftModifier) @@ -638,14 +625,14 @@ void LXQtTaskButton::contextMenuEvent(QContextMenuEvent* event) a->setEnabled(info.actionSupported(NET::ActionMaxVert) && windowState != LXQtTaskBarWindowState::MaximizedVertically && windowState != LXQtTaskBarWindowState::Hidden); - a->setData(NET::MaxVert); + a->setData(int(LXQtTaskBarWindowState::MaximizedVertically)); connect(a, &QAction::triggered, this, &LXQtTaskButton::maximizeApplication); a = menu->addAction(tr("Maximize horizontally")); a->setEnabled(info.actionSupported(NET::ActionMaxHoriz) && windowState != LXQtTaskBarWindowState::MaximizedHorizontally && windowState != LXQtTaskBarWindowState::Hidden); - a->setData(NET::MaxHoriz); + a->setData(int(LXQtTaskBarWindowState::MaximizedHorizontally)); connect(a, &QAction::triggered, this, &LXQtTaskButton::maximizeApplication); } @@ -746,7 +733,7 @@ bool LXQtTaskButton::isOnCurrentScreen() const bool LXQtTaskButton::isMinimized() const { - return KWindowInfo(mWindow,NET::WMState | NET::XAWMState).isMinimized(); + return mBackend->getWindowState(mWindow) == LXQtTaskBarWindowState::Minimized; } Qt::Corner LXQtTaskButton::origin() const From 05bb41b70fca4af275806175aef2129f401a4a05 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 28 Jan 2024 13:27:46 +0100 Subject: [PATCH 50/92] TaskBar: port workspace usage to backend --- plugin-taskbar/lxqttaskbutton.cpp | 19 ++++++++----------- plugin-taskbar/lxqttaskgroup.cpp | 4 ++-- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index 4954d6adb..fa6c8e74d 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -558,21 +558,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 @@ -583,7 +583,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); @@ -719,16 +719,13 @@ 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 { QScreen *screen = parentTaskBar()->screen(); - QRect screenGeo = screen->geometry(); - QRect windowGeo = KWindowInfo(mWindow, NET::WMFrameExtents).frameGeometry(); - - return screenGeo.intersects(windowGeo); + return mBackend->isWindowOnScreen(screen, mWindow); } bool LXQtTaskButton::isMinimized() const diff --git a/plugin-taskbar/lxqttaskgroup.cpp b/plugin-taskbar/lxqttaskgroup.cpp index 4ad7f5299..97777634b 100644 --- a/plugin-taskbar/lxqttaskgroup.cpp +++ b/plugin-taskbar/lxqttaskgroup.cpp @@ -392,7 +392,7 @@ void LXQtTaskGroup::refreshVisibility() const int showDesktop = taskbar->showDesktopNum(); 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); @@ -649,7 +649,7 @@ bool LXQtTaskGroup::onWindowChanged(WId window, NET::Properties prop, NET::Prope if (prop.testFlag(NET::WMDesktop) || prop.testFlag(NET::WMGeometry)) { if (parentTaskBar()->isShowOnlyOneDesktopTasks() - || parentTaskBar()->isShowOnlyCurrentScreenTasks()) + || parentTaskBar()->isShowOnlyCurrentScreenTasks()) { needsRefreshVisibility = true; } From 161bf922a678c4bd92feb9bcaf8df5e3831458bc Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 3 Feb 2024 18:33:09 +0100 Subject: [PATCH 51/92] TaskBar: remove X11 specific includes in lxqttaskbutton.cpp --- plugin-taskbar/lxqttaskbutton.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index fa6c8e74d..2ce754887 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -50,18 +50,9 @@ #include #include -//TODO: remove -#include - -// Necessary for closeApplication() -#include - -//NOTE: Xlib.h defines Bool which conflicts with QJsonValue::Type enum -#include -#undef Bool +#include "ilxqttaskbarabstractbackend.h" -#include "ilxqttaskbarabstractbackend.h" bool LXQtTaskButton::sDraggging = false; From 504e4612b92cf1dd7e31b1d76709560f66f984e2 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 28 Jan 2024 15:59:25 +0100 Subject: [PATCH 52/92] TaskBar: remove X11 code from LXQtTaskBar and LXQtTaskGroup --- plugin-taskbar/lxqttaskbar.cpp | 99 ++++---------------------------- plugin-taskbar/lxqttaskbar.h | 9 +-- plugin-taskbar/lxqttaskgroup.cpp | 38 ++++-------- plugin-taskbar/lxqttaskgroup.h | 5 +- 4 files changed, 28 insertions(+), 123 deletions(-) diff --git a/plugin-taskbar/lxqttaskbar.cpp b/plugin-taskbar/lxqttaskbar.cpp index fc60496a3..1bf7781f7 100644 --- a/plugin-taskbar/lxqttaskbar.cpp +++ b/plugin-taskbar/lxqttaskbar.cpp @@ -50,10 +50,6 @@ #include "lxqttaskgroup.h" #include "../panel/pluginsettings.h" -//NOTE: Xlib.h defines Bool which conflicts with QJsonValue::Type enum -#include -#undef Bool - #include "lxqttaskbarbackend_x11.h" using namespace LXQt; @@ -107,10 +103,9 @@ LXQtTaskBar::LXQtTaskBar(ILXQtPanelPlugin *plugin, QWidget *parent) : 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); } /************************************************ @@ -121,49 +116,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; - - auto *x11Application = qGuiApp->nativeInterface(); - Q_ASSERT_X(x11Application, "DesktopSwitch", "Expected X11 connection"); - WId appRootWindow = XDefaultRootWindow(x11Application->display()); - - // WM_TRANSIENT_FOR hint not set - normal window - WId transFor = info.transientFor(); - if (transFor == 0 || transFor == window || 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); -} - /************************************************ ************************************************/ @@ -328,7 +280,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) @@ -336,7 +288,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; @@ -370,43 +322,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); } } @@ -415,7 +338,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); } @@ -541,8 +464,8 @@ void LXQtTaskBar::settingsChanged() if (iconByClassOld != mIconByClass) emit iconByClassChanged(); - refreshTaskList(); //TODO: remove mBackend->reloadWindows(); + refreshPlaceholderVisibility(); } /************************************************ diff --git a/plugin-taskbar/lxqttaskbar.h b/plugin-taskbar/lxqttaskbar.h index c36bca7e0..9f94a2958 100644 --- a/plugin-taskbar/lxqttaskbar.h +++ b/plugin-taskbar/lxqttaskbar.h @@ -37,9 +37,6 @@ #include #include "../panel/ilxqtpanel.h" -#include -#include -#include class ILXQtPanel; class ILXQtPanelPlugin; @@ -107,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); @@ -150,7 +148,6 @@ private slots: int mWheelEventsAction; int mWheelDeltaThreshold; - bool acceptWindow(WId window) const; void setButtonStyle(Qt::ToolButtonStyle buttonStyle); void wheelEvent(QWheelEvent* event); diff --git a/plugin-taskbar/lxqttaskgroup.cpp b/plugin-taskbar/lxqttaskgroup.cpp index 97777634b..30babc358 100644 --- a/plugin-taskbar/lxqttaskgroup.cpp +++ b/plugin-taskbar/lxqttaskgroup.cpp @@ -41,12 +41,6 @@ #include #include #include -#include - -//TODO: remove -#include //For nativeInterface() -#include -#undef Bool #include "ilxqttaskbarabstractbackend.h" @@ -622,8 +616,10 @@ 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}; QList buttons; if (mButtonHash.contains(window)) @@ -636,17 +632,16 @@ 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()) @@ -655,40 +650,29 @@ bool LXQtTaskGroup::onWindowChanged(WId window, NET::Properties prop, NET::Prope } } - 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 (auto *x11Application = qGuiApp->nativeInterface()) - { - WId appRootWindow = XDefaultRootWindow(x11Application->display()); - urgency = NETWinInfo(x11Application->connection(), window, appRootWindow, NET::Properties{}, NET::WM2Urgency).urgency(); - } - - if (prop2.testFlag(NET::WM2Urgency)) + if (prop == LXQtTaskBarWindowProperty::Urgency) { set_urgency = true; //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}; - - // Force refresh urgency if (!set_urgency) 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 3787f411f..d4868c5d2 100644 --- a/plugin-taskbar/lxqttaskgroup.h +++ b/plugin-taskbar/lxqttaskgroup.h @@ -33,7 +33,7 @@ #include "lxqttaskbutton.h" -#include +#include "lxqttaskbartypes.h" class QVBoxLayout; class ILXQtPanelPlugin; @@ -60,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); From f0630c869833d7a7546e25374d4c3500e71074ad Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 28 Jan 2024 16:38:00 +0100 Subject: [PATCH 53/92] TaskBar: LXQtTaskButton remove X11 specific code --- plugin-taskbar/lxqttaskbutton.cpp | 68 ++++++++++++++++--------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index 2ce754887..a92d034c3 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -140,7 +140,7 @@ 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()) { @@ -516,8 +516,7 @@ void LXQtTaskButton::contextMenuEvent(QContextMenuEvent* event) return; } - KWindowInfo info(mWindow, NET::Properties(), NET::WM2AllowedActions); - NET::States state = KWindowInfo(mWindow, NET::WMState).state(); + const LXQtTaskBarWindowState state = mBackend->getWindowState(mWindow); QMenu * menu = new QMenu(tr("Application")); menu->setAttribute(Qt::WA_DeleteOnClose); @@ -586,74 +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(); - LXQtTaskBarWindowState windowState = mBackend->getWindowState(mWindow); - a = menu->addAction(tr("Ma&ximize")); - a->setEnabled(info.actionSupported(NET::ActionMax) - && windowState != LXQtTaskBarWindowState::Maximized - && windowState != LXQtTaskBarWindowState::Hidden); + 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) - && windowState != LXQtTaskBarWindowState::MaximizedVertically - && windowState != LXQtTaskBarWindowState::Hidden); + 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) - && windowState != LXQtTaskBarWindowState::MaximizedHorizontally - && windowState != LXQtTaskBarWindowState::Hidden); + 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(windowState == LXQtTaskBarWindowState::Hidden - || windowState == LXQtTaskBarWindowState::Minimized - || windowState == LXQtTaskBarWindowState::Maximized - || windowState == LXQtTaskBarWindowState::MaximizedVertically - || windowState == LXQtTaskBarWindowState::MaximizedHorizontally); + 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) - && windowState != LXQtTaskBarWindowState::Hidden - && windowState != LXQtTaskBarWindowState::Minimized); + a->setEnabled(mBackend->supportsAction(mWindow, LXQtTaskBarBackendAction::Minimize) + && state != LXQtTaskBarWindowState::Hidden + && state != LXQtTaskBarWindowState::Minimized); connect(a, &QAction::triggered, this, &LXQtTaskButton::minimizeApplication); - if (windowState == LXQtTaskBarWindowState::RolledUp) + if (state == LXQtTaskBarWindowState::RolledUp) { a = menu->addAction(tr("Roll down")); - a->setEnabled(info.actionSupported(NET::ActionShade) - && windowState != LXQtTaskBarWindowState::Hidden - && windowState != LXQtTaskBarWindowState::Minimized); + 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) - && windowState != LXQtTaskBarWindowState::Hidden); + a->setEnabled(mBackend->supportsAction(mWindow, LXQtTaskBarBackendAction::RollUp) + && state != LXQtTaskBarWindowState::Hidden); connect(a, &QAction::triggered, this, &LXQtTaskButton::shadeApplication); } @@ -664,7 +668,6 @@ void LXQtTaskButton::contextMenuEvent(QContextMenuEvent* event) LXQtTaskBarWindowLayer currentLayer = mBackend->getWindowLayer(mWindow); - // FIXME: There is no info.actionSupported(NET::ActionKeepAbove) a = layerMenu->addAction(tr("Always on &top")); a->setEnabled(currentLayer != LXQtTaskBarWindowLayer::KeepAbove); a->setData(int(LXQtTaskBarWindowLayer::KeepAbove)); @@ -675,7 +678,6 @@ void LXQtTaskButton::contextMenuEvent(QContextMenuEvent* event) a->setData(int(LXQtTaskBarWindowLayer::Normal)); connect(a, &QAction::triggered, this, &LXQtTaskButton::setApplicationLayer); - // FIXME: There is no info.actionSupported(NET::ActionKeepBelow) a = layerMenu->addAction(tr("Always on &bottom")); a->setEnabled(currentLayer != LXQtTaskBarWindowLayer::KeepBelow); a->setData(int(LXQtTaskBarWindowLayer::KeepBelow)); From 60f2b574c49ed8a8895db89b8748dc293bc9901d Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 17 Feb 2024 23:40:21 +0100 Subject: [PATCH 54/92] TaskBar: set context menu parent --- plugin-taskbar/lxqttaskbutton.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index a92d034c3..57a40f26a 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -518,7 +518,7 @@ void LXQtTaskButton::contextMenuEvent(QContextMenuEvent* event) 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; From 1bd36e09f4afbbb795889c857a97ebc027493f36 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 18 Feb 2024 00:01:15 +0100 Subject: [PATCH 55/92] LXQtPanel: rework calculatePopupWindowPos() - Don't rely on global screen coordinates - This will be needed for future Wayland port, Where we don't have global screen coordinates - Keep compatible behavior on X11 --- panel/lxqtpanel.cpp | 56 +++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/panel/lxqtpanel.cpp b/panel/lxqtpanel.cpp index 86ba83141..5f3270c41 100644 --- a/panel/lxqtpanel.cpp +++ b/panel/lxqtpanel.cpp @@ -1258,48 +1258,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 + + QRect panelScreen; + const auto screens = QApplication::screens(); + if (mActualScreenNum < screens.size()) + panelScreen = screens.at(mActualScreenNum)->geometry(); - if (res.bottom() > panelScreen.bottom()) - res.moveBottom(panelScreen.bottom()); + // 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.left() < panelScreen.left()) - res.moveLeft(panelScreen.left()); + if (res.right() > panelScreen.right()) + res.moveRight(panelScreen.right()); - if (res.top() < panelScreen.top()) - res.moveTop(panelScreen.top()); + 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 +1333,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); } From 068aa555f9abb6a28b9cc15e6f883804608f36fc Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sun, 18 Feb 2024 13:13:24 +0100 Subject: [PATCH 56/92] LXQtPanel: avoid QCursor::pos() usage --- panel/lxqtpanel.cpp | 6 +++--- panel/lxqtpanel.h | 3 ++- panel/plugin.cpp | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/panel/lxqtpanel.cpp b/panel/lxqtpanel.cpp index 5f3270c41..0835aebb4 100644 --- a/panel/lxqtpanel.cpp +++ b/panel/lxqtpanel.cpp @@ -1106,7 +1106,7 @@ bool LXQtPanel::event(QEvent *event) switch (event->type()) { case QEvent::ContextMenu: - showPopupMenu(); + showPopupMenu(static_cast(event)->globalPos()); break; case QEvent::LayoutRequest: @@ -1171,7 +1171,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 +1239,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(); } diff --git a/panel/lxqtpanel.h b/panel/lxqtpanel.h index 7d847dfa6..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; } diff --git a/panel/plugin.cpp b/panel/plugin.cpp index eb22ed431..4844bd528 100644 --- a/panel/plugin.cpp +++ b/panel/plugin.cpp @@ -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); } From 6928050a2bc173f354968d0f44a393dc1ab9e14d Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Mon, 19 Feb 2024 23:10:58 +0100 Subject: [PATCH 57/92] ILXQtTaskbarAbstractBackend: new Geometry window property This new window propery flag is needed to notify geometry changes --- plugin-taskbar/lxqttaskbarbackend_x11.cpp | 5 +++++ plugin-taskbar/lxqttaskbartypes.h | 1 + 2 files changed, 6 insertions(+) diff --git a/plugin-taskbar/lxqttaskbarbackend_x11.cpp b/plugin-taskbar/lxqttaskbarbackend_x11.cpp index cc7759f4e..bcb83bdde 100644 --- a/plugin-taskbar/lxqttaskbarbackend_x11.cpp +++ b/plugin-taskbar/lxqttaskbarbackend_x11.cpp @@ -48,6 +48,11 @@ void LXQtTaskbarX11Backend::onWindowChanged(WId windowId, NET::Properties prop, return; } + if (prop.testFlag(NET::WMGeometry)) + { + emit windowPropertyChanged(windowId, int(LXQtTaskBarWindowProperty::Geometry)); + } + if (prop2.testFlag(NET::WM2WindowClass)) { emit windowPropertyChanged(windowId, int(LXQtTaskBarWindowProperty::WindowClass)); diff --git a/plugin-taskbar/lxqttaskbartypes.h b/plugin-taskbar/lxqttaskbartypes.h index ccea42027..9e12092bb 100644 --- a/plugin-taskbar/lxqttaskbartypes.h +++ b/plugin-taskbar/lxqttaskbartypes.h @@ -22,6 +22,7 @@ enum class LXQtTaskBarWindowProperty Title = 0, Icon, State, + Geometry, Urgency, WindowClass, Workspace From 988dc736a0b4556faa61169a19007f335bb0accb Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 17 Feb 2024 12:34:05 +0100 Subject: [PATCH 58/92] Move ILXQtTaskbarAbstractBackend to panel directory - It is now a global instance --- panel/CMakeLists.txt | 15 +++++++++ panel/backends/CMakeLists.txt | 1 + .../backends}/ilxqttaskbarabstractbackend.cpp | 2 +- .../backends}/ilxqttaskbarabstractbackend.h | 0 .../backends}/lxqttaskbartypes.h | 0 panel/backends/xcb/CMakeLists.txt | 1 + .../backends/xcb}/lxqttaskbarbackend_x11.cpp | 0 .../backends/xcb}/lxqttaskbarbackend_x11.h | 2 +- panel/lxqtpanelapplication.cpp | 31 +++++++++++++++---- panel/lxqtpanelapplication.h | 4 +++ panel/lxqtpanelapplication_p.h | 3 ++ plugin-taskbar/CMakeLists.txt | 5 --- plugin-taskbar/lxqttaskbar.cpp | 9 +++--- plugin-taskbar/lxqttaskbarproxymodel.cpp | 2 +- plugin-taskbar/lxqttaskbarproxymodel.h | 2 +- plugin-taskbar/lxqttaskbutton.cpp | 2 +- plugin-taskbar/lxqttaskgroup.cpp | 2 +- plugin-taskbar/lxqttaskgroup.h | 2 +- 18 files changed, 61 insertions(+), 22 deletions(-) create mode 100644 panel/backends/CMakeLists.txt rename {plugin-taskbar => panel/backends}/ilxqttaskbarabstractbackend.cpp (90%) rename {plugin-taskbar => panel/backends}/ilxqttaskbarabstractbackend.h (100%) rename {plugin-taskbar => panel/backends}/lxqttaskbartypes.h (100%) create mode 100644 panel/backends/xcb/CMakeLists.txt rename {plugin-taskbar => panel/backends/xcb}/lxqttaskbarbackend_x11.cpp (100%) rename {plugin-taskbar => panel/backends/xcb}/lxqttaskbarbackend_x11.h (98%) diff --git a/panel/CMakeLists.txt b/panel/CMakeLists.txt index 916fced2c..c9143e20c 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,11 @@ set(PRIV_HEADERS config/configstyling.h config/configpluginswidget.h config/addplugindialog.h + + backends/ilxqttaskbarabstractbackend.h + backends/lxqttaskbartypes.h + + backends/xcb/lxqttaskbarbackend_x11.h ) # using LXQt namespace in the public headers. @@ -26,6 +34,9 @@ set(PUB_HEADERS pluginsettings.h ilxqtpanelplugin.h ilxqtpanel.h + + backends/ilxqttaskbarabstractbackend.h + backends/lxqttaskbartypes.h ) set(SOURCES @@ -45,6 +56,10 @@ set(SOURCES config/configstyling.cpp config/configpluginswidget.cpp config/addplugindialog.cpp + + backends/ilxqttaskbarabstractbackend.cpp + + backends/xcb/lxqttaskbarbackend_x11.cpp ) set(UI 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/plugin-taskbar/ilxqttaskbarabstractbackend.cpp b/panel/backends/ilxqttaskbarabstractbackend.cpp similarity index 90% rename from plugin-taskbar/ilxqttaskbarabstractbackend.cpp rename to panel/backends/ilxqttaskbarabstractbackend.cpp index d0959fb78..acf33f464 100644 --- a/plugin-taskbar/ilxqttaskbarabstractbackend.cpp +++ b/panel/backends/ilxqttaskbarabstractbackend.cpp @@ -1,4 +1,4 @@ -#include "ilxqttaskbarabstractbackend.h" +#include "../panel/backends/ilxqttaskbarabstractbackend.h" ILXQtTaskbarAbstractBackend::ILXQtTaskbarAbstractBackend(QObject *parent) diff --git a/plugin-taskbar/ilxqttaskbarabstractbackend.h b/panel/backends/ilxqttaskbarabstractbackend.h similarity index 100% rename from plugin-taskbar/ilxqttaskbarabstractbackend.h rename to panel/backends/ilxqttaskbarabstractbackend.h diff --git a/plugin-taskbar/lxqttaskbartypes.h b/panel/backends/lxqttaskbartypes.h similarity index 100% rename from plugin-taskbar/lxqttaskbartypes.h rename to panel/backends/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/plugin-taskbar/lxqttaskbarbackend_x11.cpp b/panel/backends/xcb/lxqttaskbarbackend_x11.cpp similarity index 100% rename from plugin-taskbar/lxqttaskbarbackend_x11.cpp rename to panel/backends/xcb/lxqttaskbarbackend_x11.cpp diff --git a/plugin-taskbar/lxqttaskbarbackend_x11.h b/panel/backends/xcb/lxqttaskbarbackend_x11.h similarity index 98% rename from plugin-taskbar/lxqttaskbarbackend_x11.h rename to panel/backends/xcb/lxqttaskbarbackend_x11.h index 26c721cf7..2797a7da8 100644 --- a/plugin-taskbar/lxqttaskbarbackend_x11.h +++ b/panel/backends/xcb/lxqttaskbarbackend_x11.h @@ -1,7 +1,7 @@ #ifndef LXQTTASKBARBACKEND_X11_H #define LXQTTASKBARBACKEND_X11_H -#include "ilxqttaskbarabstractbackend.h" +#include "../ilxqttaskbarabstractbackend.h" //TODO: make PIMPL to forward declare NET::Properties, Display, xcb_connection_t #include diff --git a/panel/lxqtpanelapplication.cpp b/panel/lxqtpanelapplication.cpp index 430ea6f35..2b1980d85 100644 --- a/panel/lxqtpanelapplication.cpp +++ b/panel/lxqtpanelapplication.cpp @@ -25,22 +25,35 @@ * * 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/xcb/lxqttaskbarbackend_x11.h" + +ILXQtTaskbarAbstractBackend *createWMBackend() +{ + if(qGuiApp->nativeInterface()) + return new LXQtTaskbarX11Backend; + + Q_ASSERT_X(false, "createWMBackend()", "Only X11 supported!"); + return nullptr; +} LXQtPanelApplicationPrivate::LXQtPanelApplicationPrivate(LXQtPanelApplication *q) : mSettings(nullptr), q_ptr(q) { + mWMBackend = createWMBackend(); } @@ -290,6 +303,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) { 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/plugin-taskbar/CMakeLists.txt b/plugin-taskbar/CMakeLists.txt index be434f6a6..74a00d6e6 100644 --- a/plugin-taskbar/CMakeLists.txt +++ b/plugin-taskbar/CMakeLists.txt @@ -8,9 +8,6 @@ set(HEADERS lxqttaskgroup.h lxqtgrouppopup.h - ilxqttaskbarabstractbackend.h - lxqttaskbartypes.h - lxqttaskbarbackend_x11.h lxqttaskbarproxymodel.h ) @@ -22,8 +19,6 @@ set(SOURCES lxqttaskgroup.cpp lxqtgrouppopup.cpp - ilxqttaskbarabstractbackend.cpp - lxqttaskbarbackend_x11.cpp lxqttaskbarproxymodel.cpp ) diff --git a/plugin-taskbar/lxqttaskbar.cpp b/plugin-taskbar/lxqttaskbar.cpp index 1bf7781f7..c306d796e 100644 --- a/plugin-taskbar/lxqttaskbar.cpp +++ b/plugin-taskbar/lxqttaskbar.cpp @@ -50,7 +50,8 @@ #include "lxqttaskgroup.h" #include "../panel/pluginsettings.h" -#include "lxqttaskbarbackend_x11.h" +#include "../panel/backends/ilxqttaskbarabstractbackend.h" +#include "../panel/lxqtpanelapplication.h" using namespace LXQt; @@ -93,9 +94,9 @@ LXQtTaskBar::LXQtTaskBar(ILXQtPanelPlugin *plugin, QWidget *parent) : mPlaceHolder->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); mLayout->addWidget(mPlaceHolder); - // Create model - //TODO: use backend factory - mBackend = new LXQtTaskbarX11Backend(this); + // Get backend + LXQtPanelApplication *a = static_cast(qApp); + mBackend = a->getWMBackend(); QTimer::singleShot(0, this, &LXQtTaskBar::settingsChanged); setAcceptDrops(true); diff --git a/plugin-taskbar/lxqttaskbarproxymodel.cpp b/plugin-taskbar/lxqttaskbarproxymodel.cpp index e2f1d3941..fdcdfa4d4 100644 --- a/plugin-taskbar/lxqttaskbarproxymodel.cpp +++ b/plugin-taskbar/lxqttaskbarproxymodel.cpp @@ -1,6 +1,6 @@ #include "lxqttaskbarproxymodel.h" -#include "ilxqttaskbarabstractbackend.h" +#include "../panel/backends/ilxqttaskbarabstractbackend.h" #include diff --git a/plugin-taskbar/lxqttaskbarproxymodel.h b/plugin-taskbar/lxqttaskbarproxymodel.h index be5799076..8bbb5ec49 100644 --- a/plugin-taskbar/lxqttaskbarproxymodel.h +++ b/plugin-taskbar/lxqttaskbarproxymodel.h @@ -4,7 +4,7 @@ #include #include -#include "lxqttaskbartypes.h" +#include "../panel/backends/lxqttaskbartypes.h" class ILXQtTaskbarAbstractBackend; diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index 57a40f26a..c2e2a0282 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -50,7 +50,7 @@ #include #include -#include "ilxqttaskbarabstractbackend.h" +#include "../panel/backends/ilxqttaskbarabstractbackend.h" diff --git a/plugin-taskbar/lxqttaskgroup.cpp b/plugin-taskbar/lxqttaskgroup.cpp index 30babc358..c6075df89 100644 --- a/plugin-taskbar/lxqttaskgroup.cpp +++ b/plugin-taskbar/lxqttaskgroup.cpp @@ -42,7 +42,7 @@ #include #include -#include "ilxqttaskbarabstractbackend.h" +#include "../panel/backends/ilxqttaskbarabstractbackend.h" /************************************************ diff --git a/plugin-taskbar/lxqttaskgroup.h b/plugin-taskbar/lxqttaskgroup.h index d4868c5d2..31ab784fb 100644 --- a/plugin-taskbar/lxqttaskgroup.h +++ b/plugin-taskbar/lxqttaskgroup.h @@ -33,7 +33,7 @@ #include "lxqttaskbutton.h" -#include "lxqttaskbartypes.h" +#include "../panel/backends/lxqttaskbartypes.h" class QVBoxLayout; class ILXQtPanelPlugin; From b87fe2d465e9387e62dc685f623520a35d813c2f Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Mon, 19 Feb 2024 23:17:55 +0100 Subject: [PATCH 59/92] ILXQtTaskbarAbstractBackend: new isAreaOverlapped() method --- panel/backends/ilxqttaskbarabstractbackend.h | 3 ++ panel/backends/xcb/lxqttaskbarbackend_x11.cpp | 32 +++++++++++++++++++ panel/backends/xcb/lxqttaskbarbackend_x11.h | 3 ++ 3 files changed, 38 insertions(+) diff --git a/panel/backends/ilxqttaskbarabstractbackend.h b/panel/backends/ilxqttaskbarabstractbackend.h index 932d64fc0..fb49d7b52 100644 --- a/panel/backends/ilxqttaskbarabstractbackend.h +++ b/panel/backends/ilxqttaskbarabstractbackend.h @@ -65,6 +65,9 @@ class ILXQtTaskbarAbstractBackend : public QObject virtual void refreshIconGeometry(WId windowId, const QRect &geom) = 0; + // Panel internal + virtual bool isAreaOverlapped(const QRect& area) const = 0; + signals: void reloaded(); diff --git a/panel/backends/xcb/lxqttaskbarbackend_x11.cpp b/panel/backends/xcb/lxqttaskbarbackend_x11.cpp index bcb83bdde..1d29148c8 100644 --- a/panel/backends/xcb/lxqttaskbarbackend_x11.cpp +++ b/panel/backends/xcb/lxqttaskbarbackend_x11.cpp @@ -585,3 +585,35 @@ void LXQtTaskbarX11Backend::refreshIconGeometry(WId windowId, QRect const & geom 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; +} diff --git a/panel/backends/xcb/lxqttaskbarbackend_x11.h b/panel/backends/xcb/lxqttaskbarbackend_x11.h index 2797a7da8..42e84b146 100644 --- a/panel/backends/xcb/lxqttaskbarbackend_x11.h +++ b/panel/backends/xcb/lxqttaskbarbackend_x11.h @@ -61,6 +61,9 @@ class LXQtTaskbarX11Backend : public ILXQtTaskbarAbstractBackend virtual void refreshIconGeometry(WId windowId, const QRect &geom) override; + // Panel internal + virtual bool isAreaOverlapped(const QRect& area) const override; + private slots: void onWindowChanged(WId windowId, NET::Properties prop, NET::Properties2 prop2); void onWindowAdded(WId windowId); From cc3fbe3fd157b1763997138688f6b74d1f8520d0 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Mon, 19 Feb 2024 23:11:23 +0100 Subject: [PATCH 60/92] LXQtPanel: use less KX11Extras and more ILXQtTaskbarAbstractBackend --- panel/lxqtpanel.cpp | 83 +++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 48 deletions(-) diff --git a/panel/lxqtpanel.cpp b/panel/lxqtpanel.cpp index 0835aebb4..b704fdd3d 100644 --- a/panel/lxqtpanel.cpp +++ b/panel/lxqtpanel.cpp @@ -51,7 +51,9 @@ #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 @@ -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); } @@ -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 - KX11Extras::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: @@ -1416,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) From 4b7cfd51ed443c45f829e09c825c52202c01f9a2 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Thu, 22 Feb 2024 20:32:50 +0100 Subject: [PATCH 61/92] ILXQtTaskbarAbstractBackend: add dummy implementation This will be used to avoid crashing panel in case no backend could be created. A warning message will be printed in this case. --- panel/CMakeLists.txt | 2 + panel/backends/lxqttaskbardummybackend.cpp | 156 +++++++++++++++++++++ panel/backends/lxqttaskbardummybackend.h | 82 +++++++++++ panel/lxqtpanelapplication.cpp | 10 +- 4 files changed, 248 insertions(+), 2 deletions(-) create mode 100644 panel/backends/lxqttaskbardummybackend.cpp create mode 100644 panel/backends/lxqttaskbardummybackend.h diff --git a/panel/CMakeLists.txt b/panel/CMakeLists.txt index c9143e20c..79f46497b 100644 --- a/panel/CMakeLists.txt +++ b/panel/CMakeLists.txt @@ -25,6 +25,7 @@ set(PRIV_HEADERS backends/ilxqttaskbarabstractbackend.h backends/lxqttaskbartypes.h + backends/lxqttaskbardummybackend.h backends/xcb/lxqttaskbarbackend_x11.h ) @@ -59,6 +60,7 @@ set(SOURCES backends/ilxqttaskbarabstractbackend.cpp + backends/lxqttaskbardummybackend.cpp backends/xcb/lxqttaskbarbackend_x11.cpp ) diff --git a/panel/backends/lxqttaskbardummybackend.cpp b/panel/backends/lxqttaskbardummybackend.cpp new file mode 100644 index 000000000..f91fa75bf --- /dev/null +++ b/panel/backends/lxqttaskbardummybackend.cpp @@ -0,0 +1,156 @@ +#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; +} + diff --git a/panel/backends/lxqttaskbardummybackend.h b/panel/backends/lxqttaskbardummybackend.h new file mode 100644 index 000000000..535de303b --- /dev/null +++ b/panel/backends/lxqttaskbardummybackend.h @@ -0,0 +1,82 @@ +#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; + +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/lxqtpanelapplication.cpp b/panel/lxqtpanelapplication.cpp index 2b1980d85..c3b666620 100644 --- a/panel/lxqtpanelapplication.cpp +++ b/panel/lxqtpanelapplication.cpp @@ -38,6 +38,7 @@ #include #include +#include "backends/lxqttaskbardummybackend.h" #include "backends/xcb/lxqttaskbarbackend_x11.h" ILXQtTaskbarAbstractBackend *createWMBackend() @@ -45,8 +46,13 @@ ILXQtTaskbarAbstractBackend *createWMBackend() if(qGuiApp->nativeInterface()) return new LXQtTaskbarX11Backend; - Q_ASSERT_X(false, "createWMBackend()", "Only X11 supported!"); - return nullptr; + 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) From 7730f59af76a81ce6ac5706d47ff520e43a54202 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Wed, 28 Feb 2024 20:32:04 +0100 Subject: [PATCH 62/92] LXQtMainMenu: indent header include --- plugin-mainmenu/lxqtmainmenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-mainmenu/lxqtmainmenu.cpp b/plugin-mainmenu/lxqtmainmenu.cpp index 1db7f911f..0f55cdfbd 100644 --- a/plugin-mainmenu/lxqtmainmenu.cpp +++ b/plugin-mainmenu/lxqtmainmenu.cpp @@ -54,7 +54,7 @@ #include #include #include -#include + #include #endif #define DEFAULT_SHORTCUT "Alt+F1" From 974e48127e95e87bcd67e38c67d1f17b99874a5b Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Mon, 26 Feb 2024 13:34:42 +0100 Subject: [PATCH 63/92] SNIProxy: use Qt Private headers to get Xcb timestamp --- plugin-tray/CMakeLists.txt | 1 + plugin-tray/sniproxy.cpp | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/plugin-tray/CMakeLists.txt b/plugin-tray/CMakeLists.txt index a0541e226..fc51b1b50 100644 --- a/plugin-tray/CMakeLists.txt +++ b/plugin-tray/CMakeLists.txt @@ -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/sniproxy.cpp b/plugin-tray/sniproxy.cpp index 5122b0d38..4cb05ce97 100644 --- a/plugin-tray/sniproxy.cpp +++ b/plugin-tray/sniproxy.cpp @@ -38,6 +38,7 @@ #include #include +#include //For "gettimestamp" Xcb integration resource #include "kwindowinfo.h" #include "statusnotifieritemadaptor.h" @@ -590,13 +591,17 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) 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 = XCB_CURRENT_TIME; //FIXME: how to get proper timestamp? + event->time = timeStamp; event->same_screen = 1; event->root = appRootWindow; event->root_x = x; @@ -619,7 +624,7 @@ 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 = XCB_CURRENT_TIME; //FIXME: how to get proper timestamp? + event->time = timeStamp; event->same_screen = 1; event->root = appRootWindow; event->root_x = x; From d9b58f3cfe16df8419cf59564a6a1539ba9d23a8 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Thu, 22 Feb 2024 17:12:03 +0100 Subject: [PATCH 64/92] ILXQtTaskbarAbstractBackend: new showDesktop() function --- panel/backends/ilxqttaskbarabstractbackend.h | 8 ++++++++ panel/backends/lxqttaskbardummybackend.cpp | 10 ++++++++++ panel/backends/lxqttaskbardummybackend.h | 4 ++++ panel/backends/xcb/lxqttaskbarbackend_x11.cpp | 11 +++++++++++ panel/backends/xcb/lxqttaskbarbackend_x11.h | 4 ++++ 5 files changed, 37 insertions(+) diff --git a/panel/backends/ilxqttaskbarabstractbackend.h b/panel/backends/ilxqttaskbarabstractbackend.h index fb49d7b52..7daecfe60 100644 --- a/panel/backends/ilxqttaskbarabstractbackend.h +++ b/panel/backends/ilxqttaskbarabstractbackend.h @@ -68,6 +68,14 @@ class ILXQtTaskbarAbstractBackend : public QObject // 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(); diff --git a/panel/backends/lxqttaskbardummybackend.cpp b/panel/backends/lxqttaskbardummybackend.cpp index f91fa75bf..ceaf3c334 100644 --- a/panel/backends/lxqttaskbardummybackend.cpp +++ b/panel/backends/lxqttaskbardummybackend.cpp @@ -154,3 +154,13 @@ 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 index 535de303b..d4e1ca4bc 100644 --- a/panel/backends/lxqttaskbardummybackend.h +++ b/panel/backends/lxqttaskbardummybackend.h @@ -62,6 +62,10 @@ class LXQtTaskBarDummyBackend : public ILXQtTaskbarAbstractBackend // Panel internal bool isAreaOverlapped(const QRect& area) const override; + // Show Destop + bool isShowingDesktop() const override; + bool showDesktop(bool value) override; + signals: void reloaded(); diff --git a/panel/backends/xcb/lxqttaskbarbackend_x11.cpp b/panel/backends/xcb/lxqttaskbarbackend_x11.cpp index 1d29148c8..822afed51 100644 --- a/panel/backends/xcb/lxqttaskbarbackend_x11.cpp +++ b/panel/backends/xcb/lxqttaskbarbackend_x11.cpp @@ -617,3 +617,14 @@ bool LXQtTaskbarX11Backend::isAreaOverlapped(const QRect &area) const } 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 index 42e84b146..8106cda9f 100644 --- a/panel/backends/xcb/lxqttaskbarbackend_x11.h +++ b/panel/backends/xcb/lxqttaskbarbackend_x11.h @@ -64,6 +64,10 @@ class LXQtTaskbarX11Backend : public ILXQtTaskbarAbstractBackend // 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); From a3e93e2d01d0924fe967c67cc847bae603937a1a Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Thu, 22 Feb 2024 17:12:28 +0100 Subject: [PATCH 65/92] ShowDesktop: use ILXQtTaskbarAbstractBackend --- plugin-showdesktop/showdesktop.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugin-showdesktop/showdesktop.cpp b/plugin-showdesktop/showdesktop.cpp index 871da62ea..fb69f6067 100644 --- a/plugin-showdesktop/showdesktop.cpp +++ b/plugin-showdesktop/showdesktop.cpp @@ -29,11 +29,12 @@ #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) : @@ -69,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 From 56aed45eaad6716e8f3c45232aefc77abdffaf19 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 23 Feb 2024 12:27:28 +0100 Subject: [PATCH 66/92] DesktopSwitch: port to ILXQtTaskbarAbstractBackend - Clarify desktop index range --- .../backends/ilxqttaskbarabstractbackend.cpp | 2 +- panel/backends/ilxqttaskbarabstractbackend.h | 1 + plugin-desktopswitch/desktopswitch.cpp | 141 ++++++++---------- plugin-desktopswitch/desktopswitch.h | 34 ++--- 4 files changed, 79 insertions(+), 99 deletions(-) diff --git a/panel/backends/ilxqttaskbarabstractbackend.cpp b/panel/backends/ilxqttaskbarabstractbackend.cpp index acf33f464..137728263 100644 --- a/panel/backends/ilxqttaskbarabstractbackend.cpp +++ b/panel/backends/ilxqttaskbarabstractbackend.cpp @@ -17,7 +17,7 @@ void ILXQtTaskbarAbstractBackend::moveApplicationToPrevNextDesktop(WId windowId, // Wrap around if (targetWorkspace > count) - targetWorkspace = 1; //TODO: are X11 desktops 1 based? + targetWorkspace = 1; //Ids are 1-based else if (targetWorkspace < 1) targetWorkspace = count; diff --git a/panel/backends/ilxqttaskbarabstractbackend.h b/panel/backends/ilxqttaskbarabstractbackend.h index 7daecfe60..fe3368363 100644 --- a/panel/backends/ilxqttaskbarabstractbackend.h +++ b/panel/backends/ilxqttaskbarabstractbackend.h @@ -45,6 +45,7 @@ class ILXQtTaskbarAbstractBackend : public QObject 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; diff --git a/plugin-desktopswitch/desktopswitch.cpp b/plugin-desktopswitch/desktopswitch.cpp index 4bd05e08f..67f6e56eb 100644 --- a/plugin-desktopswitch/desktopswitch.cpp +++ b/plugin-desktopswitch/desktopswitch.cpp @@ -25,6 +25,7 @@ * * END_COMMON_COPYRIGHT_HEADER */ +#include #include #include #include @@ -33,6 +34,8 @@ #include #include +#include "../panel/lxqtpanelapplication.h" +#include "../panel/backends/ilxqttaskbarabstractbackend.h" #include @@ -40,29 +43,22 @@ #include "desktopswitchbutton.h" #include "desktopswitchconfiguration.h" -#include -#include -#include - -//NOTE: Xlib.h defines Bool which conflicts with QJsonValue::Type enum -#include -#undef Bool - static const QString DEFAULT_SHORTCUT_TEMPLATE(QStringLiteral("Control+F%1")); 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(nullptr), mLabelType(static_cast(-1)) { - auto *x11Application = qGuiApp->nativeInterface(); - Q_ASSERT_X(x11Application, "DesktopSwitch", "Expected X11 connection"); - mDesktops.reset(new NETRootInfo(x11Application->connection(), NET::NumberOfDesktops | NET::CurrentDesktop | NET::DesktopNames, NET::WM2DesktopLayout)); + LXQtPanelApplication *a = reinterpret_cast(qApp); + mBackend = a->getWMBackend(); + + + m_desktopCount = mBackend->getWorkspacesCount(); m_buttons = new QButtonGroup(this); @@ -74,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() @@ -126,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)); } } } @@ -148,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 @@ -156,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); } @@ -167,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); @@ -185,56 +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; - - auto *x11Application = qGuiApp->nativeInterface(); - Q_ASSERT_X(x11Application, "DesktopSwitch", "Expected X11 connection"); - WId appRootWindow = XDefaultRootWindow(x11Application->display()); - - // WM_TRANSIENT_FOR hint not set - normal window - WId transFor = info.transientFor(); - if (transFor == 0 || transFor == window || 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); + // 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(); @@ -293,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 } @@ -345,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; @@ -356,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 93a930dc2..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; - std::unique_ptr 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 From f0b0d1bc545b6f0437bca0b67f99ee6bca93e897 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 23 Feb 2024 13:39:46 +0100 Subject: [PATCH 67/92] LXQtTaskbarConfiguration: port to ILXQtTaskBarAbstractBackend --- plugin-taskbar/lxqttaskbarconfiguration.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/plugin-taskbar/lxqttaskbarconfiguration.cpp b/plugin-taskbar/lxqttaskbarconfiguration.cpp index b346bb69d..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())); From c1b21d6f254c536893df6511b07176b0a679ec3b Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 23 Feb 2024 14:07:05 +0100 Subject: [PATCH 68/92] DesktopSwitchConfiguration: port to ILXQtTaskBarAbstractBackend TODO TODO: this will disable changing desktop names --- .../desktopswitchconfiguration.cpp | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/plugin-desktopswitch/desktopswitchconfiguration.cpp b/plugin-desktopswitch/desktopswitchconfiguration.cpp index 943dbdd6b..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(); }); } } From ad3ee82ad31220d1f41dda160d48f286bdaceceb Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Thu, 22 Feb 2024 17:41:16 +0100 Subject: [PATCH 69/92] TaskBar: consider initial windows --- plugin-taskbar/lxqttaskbar.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugin-taskbar/lxqttaskbar.cpp b/plugin-taskbar/lxqttaskbar.cpp index c306d796e..43090c396 100644 --- a/plugin-taskbar/lxqttaskbar.cpp +++ b/plugin-taskbar/lxqttaskbar.cpp @@ -107,6 +107,13 @@ LXQtTaskBar::LXQtTaskBar(ILXQtPanelPlugin *plugin, QWidget *parent) : 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); + } } /************************************************ From 3a64a010063fb59b13db8ded308450fa68341e0b Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 17 Feb 2024 19:18:09 +0100 Subject: [PATCH 70/92] TaskBar: add experimental KWin Wayland backend NOTE: works only on KWin - Choose backend at runtime - Windows filter logic is re-evaluated on window property changes --- panel/CMakeLists.txt | 20 + panel/backends/CMakeLists.txt | 1 + panel/backends/wayland/CMakeLists.txt | 1 + .../wayland/lxqttaskbarbackendwayland.cpp | 626 +++++++++ .../wayland/lxqttaskbarbackendwayland.h | 87 ++ .../lxqttaskbarplasmawindowmanagment.cpp | 1146 +++++++++++++++++ .../lxqttaskbarplasmawindowmanagment.h | 154 +++ .../protocols/plasma-window-management.xml | 425 ++++++ panel/lxqtpanelapplication.cpp | 3 + 9 files changed, 2463 insertions(+) create mode 100644 panel/backends/wayland/CMakeLists.txt create mode 100644 panel/backends/wayland/lxqttaskbarbackendwayland.cpp create mode 100644 panel/backends/wayland/lxqttaskbarbackendwayland.h create mode 100644 panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp create mode 100644 panel/backends/wayland/lxqttaskbarplasmawindowmanagment.h create mode 100644 panel/backends/wayland/protocols/plasma-window-management.xml diff --git a/panel/CMakeLists.txt b/panel/CMakeLists.txt index 79f46497b..6fb7c7608 100644 --- a/panel/CMakeLists.txt +++ b/panel/CMakeLists.txt @@ -3,6 +3,10 @@ set(PROJECT lxqt-panel) # TODO add_subdirectory(backends) +# TODO: move to backend folder +find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS WaylandClient Concurrent) + + set(PRIV_HEADERS panelpluginsmodel.h windownotifier.h @@ -26,7 +30,11 @@ set(PRIV_HEADERS backends/lxqttaskbartypes.h backends/lxqttaskbardummybackend.h + backends/xcb/lxqttaskbarbackend_x11.h + + backends/wayland/lxqttaskbarbackendwayland.h + backends/wayland/lxqttaskbarplasmawindowmanagment.h ) # using LXQt namespace in the public headers. @@ -61,7 +69,11 @@ set(SOURCES backends/ilxqttaskbarabstractbackend.cpp backends/lxqttaskbardummybackend.cpp + backends/xcb/lxqttaskbarbackend_x11.cpp + + backends/wayland/lxqttaskbarbackendwayland.cpp + backends/wayland/lxqttaskbarplasmawindowmanagment.cpp ) set(UI @@ -116,10 +128,18 @@ add_executable(${PROJECT} ${UI} ) +# TODO: move to backend folder +qt6_generate_wayland_protocol_client_sources(${PROJECT} +FILES + ${CMAKE_CURRENT_SOURCE_DIR}/backends/wayland/protocols/plasma-window-management.xml +) + target_link_libraries(${PROJECT} ${LIBRARIES} ${QTX_LIBRARIES} KF6::WindowSystem + Qt6::WaylandClient # TODO: Move to backend folder + Qt6::Concurrent ${STATIC_PLUGINS} ) diff --git a/panel/backends/CMakeLists.txt b/panel/backends/CMakeLists.txt index 8f34a3c67..f1915b823 100644 --- a/panel/backends/CMakeLists.txt +++ b/panel/backends/CMakeLists.txt @@ -1 +1,2 @@ +add_subdirectory(wayland) add_subdirectory(xcb) diff --git a/panel/backends/wayland/CMakeLists.txt b/panel/backends/wayland/CMakeLists.txt new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/panel/backends/wayland/CMakeLists.txt @@ -0,0 +1 @@ + diff --git a/panel/backends/wayland/lxqttaskbarbackendwayland.cpp b/panel/backends/wayland/lxqttaskbarbackendwayland.cpp new file mode 100644 index 000000000..a2a415504 --- /dev/null +++ b/panel/backends/wayland/lxqttaskbarbackendwayland.cpp @@ -0,0 +1,626 @@ +#include "lxqttaskbarbackendwayland.h" + +#include "lxqttaskbarplasmawindowmanagment.h" + +#include +#include +#include + +auto findWindow(const std::vector>& windows, LXQtTaskBarPlasmaWindow *window) +{ + //TODO: use algorithms + auto end = windows.end(); + for(auto it = windows.begin(); it != end; it++) + { + if((*it).get() == window) + { + return it; + } + } + + return windows.end(); +} + +LXQtTaskbarWaylandBackend::LXQtTaskbarWaylandBackend(QObject *parent) : + ILXQtTaskbarAbstractBackend(parent) +{ + m_managment.reset(new LXQtTaskBarPlasmaWindowManagment); + + connect(m_managment.get(), &LXQtTaskBarPlasmaWindowManagment::windowCreated, this, [this](LXQtTaskBarPlasmaWindow *window) { + connect(window, &LXQtTaskBarPlasmaWindow::initialStateDone, this, [this, window] { + addWindow(window); + }); + }); + + // connect(m_managment.get(), &LXQtTaskBarPlasmaWindowManagment::stackingOrderChanged, + // this, [this](const QString &order) { + // // stackingOrder = order.split(QLatin1Char(';')); + // // for (const auto &window : std::as_const(windows)) { + // // this->dataChanged(window.get(), StackingOrder); + // // } + // }); +} + +bool LXQtTaskbarWaylandBackend::supportsAction(WId windowId, LXQtTaskBarBackendAction action) const +{ + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return false; + + LXQtTaskBarPlasmaWindow::state state; + + switch (action) + { + case LXQtTaskBarBackendAction::Move: + state = LXQtTaskBarPlasmaWindow::state::state_movable; + break; + + case LXQtTaskBarBackendAction::Resize: + state = LXQtTaskBarPlasmaWindow::state::state_resizable; + break; + + case LXQtTaskBarBackendAction::Maximize: + state = LXQtTaskBarPlasmaWindow::state::state_maximizable; + break; + + case LXQtTaskBarBackendAction::Minimize: + state = LXQtTaskBarPlasmaWindow::state::state_minimizable; + break; + + case LXQtTaskBarBackendAction::RollUp: + state = LXQtTaskBarPlasmaWindow::state::state_shadeable; + break; + + case LXQtTaskBarBackendAction::FullScreen: + state = LXQtTaskBarPlasmaWindow::state::state_fullscreenable; + break; + + default: + return false; + } + + return window->windowState.testFlag(state); +} + +bool LXQtTaskbarWaylandBackend::reloadWindows() +{ + return false; //TODO +} + +QVector LXQtTaskbarWaylandBackend::getCurrentWindows() const +{ + QVector wids(windows.size()); + for(const auto& window : std::as_const(windows)) + { + wids << window->getWindowId(); + } + return wids; +} + +QString LXQtTaskbarWaylandBackend::getWindowTitle(WId windowId) const +{ + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return QString(); + + return window->title; +} + +bool LXQtTaskbarWaylandBackend::applicationDemandsAttention(WId windowId) const +{ + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return false; + + return window->windowState.testFlag(LXQtTaskBarPlasmaWindow::state::state_demands_attention) || transientsDemandingAttention.contains(window); +} + +QIcon LXQtTaskbarWaylandBackend::getApplicationIcon(WId windowId, int devicePixels) const +{ + Q_UNUSED(devicePixels) + + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return QIcon(); + + return window->icon; +} + +QString LXQtTaskbarWaylandBackend::getWindowClass(WId windowId) const +{ + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return QString(); + return window->appId; +} + +LXQtTaskBarWindowLayer LXQtTaskbarWaylandBackend::getWindowLayer(WId windowId) const +{ + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return LXQtTaskBarWindowLayer::Normal; + + if(window->windowState.testFlag(LXQtTaskBarPlasmaWindow::state::state_keep_above)) + return LXQtTaskBarWindowLayer::KeepAbove; + + if(window->windowState.testFlag(LXQtTaskBarPlasmaWindow::state::state_keep_below)) + return LXQtTaskBarWindowLayer::KeepBelow; + + return LXQtTaskBarWindowLayer::Normal; +} + +bool LXQtTaskbarWaylandBackend::setWindowLayer(WId windowId, LXQtTaskBarWindowLayer layer) +{ + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return false; + + if(getWindowLayer(windowId) == layer) + return true; //TODO: make more efficient + + LXQtTaskBarPlasmaWindow::state plasmaState = LXQtTaskBarPlasmaWindow::state::state_keep_above; + switch (layer) + { + case LXQtTaskBarWindowLayer::Normal: + case LXQtTaskBarWindowLayer::KeepAbove: + break; + case LXQtTaskBarWindowLayer::KeepBelow: + plasmaState = LXQtTaskBarPlasmaWindow::state::state_keep_below; + break; + default: + return false; + } + + window->set_state(plasmaState, layer == LXQtTaskBarWindowLayer::Normal ? 0 : plasmaState); + return false; +} + +LXQtTaskBarWindowState LXQtTaskbarWaylandBackend::getWindowState(WId windowId) const +{ + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return LXQtTaskBarWindowState::Normal; + + if(window->windowState.testFlag(LXQtTaskBarPlasmaWindow::state::state_minimized)) + return LXQtTaskBarWindowState::Hidden; + if(window->windowState.testFlag(LXQtTaskBarPlasmaWindow::state::state_maximizable)) + return LXQtTaskBarWindowState::Maximized; + if(window->windowState.testFlag(LXQtTaskBarPlasmaWindow::state::state_shaded)) + return LXQtTaskBarWindowState::RolledUp; + if(window->windowState.testFlag(LXQtTaskBarPlasmaWindow::state::state_fullscreen)) + return LXQtTaskBarWindowState::FullScreen; + + return LXQtTaskBarWindowState::Normal; +} + +bool LXQtTaskbarWaylandBackend::setWindowState(WId windowId, LXQtTaskBarWindowState state, bool set) +{ + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return false; + + LXQtTaskBarPlasmaWindow::state plasmaState; + switch (state) + { + case LXQtTaskBarWindowState::Minimized: + { + plasmaState = LXQtTaskBarPlasmaWindow::state::state_minimized; + break; + } + case LXQtTaskBarWindowState::Maximized: + case LXQtTaskBarWindowState::MaximizedVertically: + case LXQtTaskBarWindowState::MaximizedHorizontally: + { + plasmaState = LXQtTaskBarPlasmaWindow::state::state_maximized; + break; + } + case LXQtTaskBarWindowState::Normal: + { + plasmaState = LXQtTaskBarPlasmaWindow::state::state_maximized; + set = !set; //TODO: correct + break; + } + case LXQtTaskBarWindowState::RolledUp: + { + plasmaState = LXQtTaskBarPlasmaWindow::state::state_shaded; + break; + } + default: + return false; + } + + window->set_state(plasmaState, set ? plasmaState : 0); + return true; +} + +bool LXQtTaskbarWaylandBackend::isWindowActive(WId windowId) const +{ + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return false; + + return activeWindow == window || window->windowState.testFlag(LXQtTaskBarPlasmaWindow::state::state_active); +} + +bool LXQtTaskbarWaylandBackend::raiseWindow(WId windowId, bool onCurrentWorkSpace) +{ + Q_UNUSED(onCurrentWorkSpace) //TODO + + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return false; + + // Pull forward any transient demanding attention. + if (auto *transientDemandingAttention = transientsDemandingAttention.value(window)) + { + window = transientDemandingAttention; + } + else + { + // TODO Shouldn't KWin take care of that? + // Bringing a transient to the front usually brings its parent with it + // but focus is not handled properly. + // TODO take into account d->lastActivation instead + // of just taking the first one. + while (transients.key(window)) + { + window = transients.key(window); + } + } + + window->set_state(LXQtTaskBarPlasmaWindow::state::state_active, LXQtTaskBarPlasmaWindow::state::state_active); + return true; +} + +bool LXQtTaskbarWaylandBackend::closeWindow(WId windowId) +{ + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return false; + + window->close(); + return true; +} + +WId LXQtTaskbarWaylandBackend::getActiveWindow() const +{ + if(activeWindow) + return activeWindow->getWindowId(); + return 0; +} + +int LXQtTaskbarWaylandBackend::getWorkspacesCount() const +{ + return 1; //TODO +} + +QString LXQtTaskbarWaylandBackend::getWorkspaceName(int idx) const +{ + return QStringLiteral("TestWorkspace"); +} + +int LXQtTaskbarWaylandBackend::getCurrentWorkspace() const +{ + return 0; //TODO +} + +bool LXQtTaskbarWaylandBackend::setCurrentWorkspace(int idx) +{ + Q_UNUSED(idx) + return false; //TODO +} + +int LXQtTaskbarWaylandBackend::getWindowWorkspace(WId windowId) const +{ + Q_UNUSED(windowId) + return 0; //TODO +} + +bool LXQtTaskbarWaylandBackend::setWindowOnWorkspace(WId windowId, int idx) +{ + Q_UNUSED(windowId) + Q_UNUSED(idx) + return false; //TODO +} + +void LXQtTaskbarWaylandBackend::moveApplicationToPrevNextMonitor(WId windowId, bool next, bool raiseOnCurrentDesktop) +{ + +} + +bool LXQtTaskbarWaylandBackend::isWindowOnScreen(QScreen *screen, WId windowId) const +{ + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return false; + + return screen->geometry().intersects(window->geometry); +} + +void LXQtTaskbarWaylandBackend::moveApplication(WId windowId) +{ + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return; + + window->set_state(LXQtTaskBarPlasmaWindow::state::state_active, LXQtTaskBarPlasmaWindow::state::state_active); + window->request_move(); +} + +void LXQtTaskbarWaylandBackend::resizeApplication(WId windowId) +{ + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return; + + window->set_state(LXQtTaskBarPlasmaWindow::state::state_active, LXQtTaskBarPlasmaWindow::state::state_active); + window->request_resize(); +} + +void LXQtTaskbarWaylandBackend::refreshIconGeometry(WId windowId, const QRect &geom) +{ + +} + +bool LXQtTaskbarWaylandBackend::isAreaOverlapped(const QRect &area) const +{ + for(auto &window : std::as_const(windows)) + { + if(window->geometry.intersects(area)) + return true; + } + return false; +} + +void LXQtTaskbarWaylandBackend::addWindow(LXQtTaskBarPlasmaWindow *window) +{ + if (findWindow(windows, window) != windows.end() || transients.contains(window)) + { + return; + } + + auto removeWindow = [window, this] + { + auto it = findWindow(windows, window); + if (it != windows.end()) + { + if(window->acceptedInTaskBar) + emit windowRemoved(window->getWindowId()); + windows.erase(it); + transientsDemandingAttention.remove(window); + lastActivated.remove(window); + } + else + { + // Could be a transient. + // Removing a transient might change the demands attention state of the leader. + if (transients.remove(window)) + { + if (LXQtTaskBarPlasmaWindow *leader = transientsDemandingAttention.key(window)) { + transientsDemandingAttention.remove(leader, window); + emit windowPropertyChanged(leader->getWindowId(), int(LXQtTaskBarWindowProperty::Urgency)); + } + } + } + + if (activeWindow == window) + { + activeWindow = nullptr; + emit activeWindowChanged(0); + } + }; + + connect(window, &LXQtTaskBarPlasmaWindow::unmapped, this, removeWindow); + + connect(window, &LXQtTaskBarPlasmaWindow::titleChanged, this, [window, this] { + updateWindowAcceptance(window); + if(window->acceptedInTaskBar) + emit windowPropertyChanged(window->getWindowId(), int(LXQtTaskBarWindowProperty::Title)); + }); + + connect(window, &LXQtTaskBarPlasmaWindow::iconChanged, this, [window, this] { + updateWindowAcceptance(window); + if(window->acceptedInTaskBar) + emit windowPropertyChanged(window->getWindowId(), int(LXQtTaskBarWindowProperty::Icon)); + }); + + connect(window, &LXQtTaskBarPlasmaWindow::geometryChanged, this, [window, this] { + updateWindowAcceptance(window); + if(window->acceptedInTaskBar) + emit windowPropertyChanged(window->getWindowId(), int(LXQtTaskBarWindowProperty::Geometry)); + }); + + connect(window, &LXQtTaskBarPlasmaWindow::appIdChanged, this, [window, this] { + emit windowPropertyChanged(window->getWindowId(), int(LXQtTaskBarWindowProperty::WindowClass)); + }); + + if (window->windowState & LXQtTaskBarPlasmaWindow::state::state_active) { + LXQtTaskBarPlasmaWindow *effectiveActive = window; + while (effectiveActive->parentWindow) { + effectiveActive = effectiveActive->parentWindow; + } + + lastActivated[effectiveActive] = QTime::currentTime(); + activeWindow = effectiveActive; + } + + connect(window, &LXQtTaskBarPlasmaWindow::activeChanged, this, [window, this] { + const bool active = window->windowState & LXQtTaskBarPlasmaWindow::state::state_active; + + LXQtTaskBarPlasmaWindow *effectiveWindow = window; + + while (effectiveWindow->parentWindow) + { + effectiveWindow = effectiveWindow->parentWindow; + } + + if (active) + { + lastActivated[effectiveWindow] = QTime::currentTime(); + + if (activeWindow != effectiveWindow) + { + activeWindow = effectiveWindow; + emit activeWindowChanged(activeWindow->getWindowId()); + } + } + else + { + if (activeWindow == effectiveWindow) + { + activeWindow = nullptr; + emit activeWindowChanged(0); + } + } + }); + + connect(window, &LXQtTaskBarPlasmaWindow::parentWindowChanged, this, [window, this] { + LXQtTaskBarPlasmaWindow *leader = window->parentWindow.data(); + + // Migrate demanding attention to new leader. + if (window->windowState.testFlag(LXQtTaskBarPlasmaWindow::state::state_demands_attention)) + { + if (auto *oldLeader = transientsDemandingAttention.key(window)) + { + if (window->parentWindow != oldLeader) + { + transientsDemandingAttention.remove(oldLeader, window); + transientsDemandingAttention.insert(leader, window); + emit windowPropertyChanged(oldLeader->getWindowId(), int(LXQtTaskBarWindowProperty::Urgency)); + emit windowPropertyChanged(leader->getWindowId(), int(LXQtTaskBarWindowProperty::Urgency)); + } + } + } + + if (transients.remove(window)) + { + if (leader) + { + // leader change. + transients.insert(window, leader); + } + else + { + // lost a leader, add to regular windows list. + Q_ASSERT(findWindow(windows, window) == windows.end()); + + windows.emplace_back(window); + } + } + else if (leader) + { + // gained a leader, remove from regular windows list. + auto it = findWindow(windows, window); + Q_ASSERT(it != windows.end()); + + windows.erase(it); + lastActivated.remove(window); + } + }); + + auto stateChanged = [window, this] { + updateWindowAcceptance(window); + if(window->acceptedInTaskBar) + emit windowPropertyChanged(window->getWindowId(), int(LXQtTaskBarWindowProperty::State)); + }; + + connect(window, &LXQtTaskBarPlasmaWindow::fullscreenChanged, this, stateChanged); + + connect(window, &LXQtTaskBarPlasmaWindow::maximizedChanged, this, stateChanged); + + connect(window, &LXQtTaskBarPlasmaWindow::minimizedChanged, this, stateChanged); + + connect(window, &LXQtTaskBarPlasmaWindow::shadedChanged, this, stateChanged); + + auto workspaceChanged = [window, this] { + updateWindowAcceptance(window); + if(window->acceptedInTaskBar) + emit windowPropertyChanged(window->getWindowId(), int(LXQtTaskBarWindowProperty::Workspace)); + }; + + connect(window, &LXQtTaskBarPlasmaWindow::virtualDesktopEntered, this, workspaceChanged); + connect(window, &LXQtTaskBarPlasmaWindow::virtualDesktopLeft, this, workspaceChanged); + + connect(window, &LXQtTaskBarPlasmaWindow::demandsAttentionChanged, this, [window, this] { + // Changes to a transient's state might change demands attention state for leader. + if (auto *leader = transients.value(window)) + { + if (window->windowState.testFlag(LXQtTaskBarPlasmaWindow::state::state_demands_attention)) + { + if (!transientsDemandingAttention.values(leader).contains(window)) + { + transientsDemandingAttention.insert(leader, window); + emit windowPropertyChanged(leader->getWindowId(), int(LXQtTaskBarWindowProperty::Urgency)); + } + } + else if (transientsDemandingAttention.remove(window)) + { + emit windowPropertyChanged(leader->getWindowId(), int(LXQtTaskBarWindowProperty::Urgency)); + } + } + else + { + emit windowPropertyChanged(window->getWindowId(), int(LXQtTaskBarWindowProperty::Urgency)); + } + }); + + connect(window, &LXQtTaskBarPlasmaWindow::skipTaskbarChanged, this, [window, this] { + updateWindowAcceptance(window); + }); + + // QObject::connect(window, &PlasmaWindow::applicationMenuChanged, q, [window, this] { + // this->dataChanged(window, QList{ApplicationMenuServiceName, ApplicationMenuObjectPath}); + // }); + + // Handle transient. + if (LXQtTaskBarPlasmaWindow *leader = window->parentWindow.data()) + { + transients.insert(window, leader); + + // Update demands attention state for leader. + if (window->windowState.testFlag(LXQtTaskBarPlasmaWindow::state::state_demands_attention)) + { + transientsDemandingAttention.insert(leader, window); + if(leader->acceptedInTaskBar) + emit windowPropertyChanged(leader->getWindowId(), int(LXQtTaskBarWindowProperty::Urgency)); + } + } + else + { + windows.emplace_back(window); + updateWindowAcceptance(window); + } +} + +bool LXQtTaskbarWaylandBackend::acceptWindow(LXQtTaskBarPlasmaWindow *window) const +{ + if(window->windowState.testFlag(LXQtTaskBarPlasmaWindow::state::state_skiptaskbar)) + return false; + + return true; +} + +void LXQtTaskbarWaylandBackend::updateWindowAcceptance(LXQtTaskBarPlasmaWindow *window) +{ + if(!window->acceptedInTaskBar && acceptWindow(window)) + { + window->acceptedInTaskBar = true; + emit windowAdded(window->getWindowId()); + } + else if(window->acceptedInTaskBar && !acceptWindow(window)) + { + window->acceptedInTaskBar = false; + emit windowRemoved(window->getWindowId()); + } +} + +LXQtTaskBarPlasmaWindow *LXQtTaskbarWaylandBackend::getWindow(WId windowId) const +{ + for(auto &window : std::as_const(windows)) + { + if(window->getWindowId() == windowId) + return window.get(); + } + + return nullptr; +} diff --git a/panel/backends/wayland/lxqttaskbarbackendwayland.h b/panel/backends/wayland/lxqttaskbarbackendwayland.h new file mode 100644 index 000000000..553a7e585 --- /dev/null +++ b/panel/backends/wayland/lxqttaskbarbackendwayland.h @@ -0,0 +1,87 @@ +#ifndef LXQTTASKBARBACKENDWAYLAND_H +#define LXQTTASKBARBACKENDWAYLAND_H + +#include "../ilxqttaskbarabstractbackend.h" + +#include +#include + +class LXQtTaskBarPlasmaWindow; +class LXQtTaskBarPlasmaWindowManagment; + + +class LXQtTaskbarWaylandBackend : public ILXQtTaskbarAbstractBackend +{ + Q_OBJECT + +public: + explicit LXQtTaskbarWaylandBackend(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; + +private: + void addWindow(LXQtTaskBarPlasmaWindow *window); + bool acceptWindow(LXQtTaskBarPlasmaWindow *window) const; + void updateWindowAcceptance(LXQtTaskBarPlasmaWindow *window); + +private: + LXQtTaskBarPlasmaWindow *getWindow(WId windowId) const; + + std::unique_ptr m_managment; + + QHash lastActivated; + LXQtTaskBarPlasmaWindow *activeWindow = nullptr; + std::vector> windows; + // key=transient child, value=leader + QHash transients; + // key=leader, values=transient children + QMultiHash transientsDemandingAttention; +}; + +#endif // LXQTTASKBARBACKENDWAYLAND_H diff --git a/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp b/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp new file mode 100644 index 000000000..0a282eadd --- /dev/null +++ b/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp @@ -0,0 +1,1146 @@ +#include "lxqttaskbarplasmawindowmanagment.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +// QUuid WaylandTasksModel::Private::uuid = QUuid::createUuid(); + +// WaylandTasksModel::Private::Private(WaylandTasksModel *q) +// : q(q) +// { +// } + +// void WaylandTasksModel::Private::init() +// { +// auto clearCacheAndRefresh = [this] { +// if (windows.empty()) { +// return; +// } + +// appDataCache.clear(); + +// // Emit changes of all roles satisfied from app data cache. +// Q_EMIT q->dataChanged(q->index(0, 0), +// q->index(windows.size() - 1, 0), +// QList{Qt::DecorationRole, +// AbstractTasksModel::AppId, +// AbstractTasksModel::AppName, +// AbstractTasksModel::GenericName, +// AbstractTasksModel::LauncherUrl, +// AbstractTasksModel::LauncherUrlWithoutIcon, +// AbstractTasksModel::CanLaunchNewInstance, +// AbstractTasksModel::SkipTaskbar}); +// }; + +// rulesConfig = KSharedConfig::openConfig(QStringLiteral("taskmanagerrulesrc")); +// configWatcher = new KDirWatch(q); + +// for (const QString &location : QStandardPaths::standardLocations(QStandardPaths::ConfigLocation)) { +// configWatcher->addFile(location + QLatin1String("/taskmanagerrulesrc")); +// } + +// auto rulesConfigChange = [this, clearCacheAndRefresh] { +// rulesConfig->reparseConfiguration(); +// clearCacheAndRefresh(); +// }; + +// QObject::connect(configWatcher, &KDirWatch::dirty, rulesConfigChange); +// QObject::connect(configWatcher, &KDirWatch::created, rulesConfigChange); +// QObject::connect(configWatcher, &KDirWatch::deleted, rulesConfigChange); + +// virtualDesktopInfo = new VirtualDesktopInfo(q); + +// initWayland(); +// } + +// void WaylandTasksModel::Private::initWayland() +// { +// if (!KWindowSystem::isPlatformWayland()) { +// return; +// } + +// windowManagement = std::make_unique(); + +// QObject::connect(windowManagement.get(), &PlasmaWindowManagement::activeChanged, q, [this] { +// q->beginResetModel(); +// windows.clear(); +// q->endResetModel(); +// }); + +// QObject::connect(windowManagement.get(), &PlasmaWindowManagement::windowCreated, q, [this](PlasmaWindow *window) { +// connect(window, &PlasmaWindow::initialStateDone, q, [this, window] { +// addWindow(window); +// }); +// }); + +// QObject::connect(windowManagement.get(), &PlasmaWindowManagement::stackingOrderChanged, q, [this](const QString &order) { +// stackingOrder = order.split(QLatin1Char(';')); +// for (const auto &window : std::as_const(windows)) { +// this->dataChanged(window.get(), StackingOrder); +// } +// }); +// } + +// auto WaylandTasksModel::Private::findWindow(PlasmaWindow *window) const +// { +// return std::find_if(windows.begin(), windows.end(), [window](const std::unique_ptr &candidate) { +// return candidate.get() == window; +// }); +// } + +// void WaylandTasksModel::Private::addWindow(PlasmaWindow *window) +// { +// if (findWindow(window) != windows.end() || transients.contains(window)) { +// return; +// } + +// auto removeWindow = [window, this] { +// auto it = findWindow(window); +// if (it != windows.end()) { +// const int row = it - windows.begin(); +// q->beginRemoveRows(QModelIndex(), row, row); +// windows.erase(it); +// transientsDemandingAttention.remove(window); +// appDataCache.remove(window); +// lastActivated.remove(window); +// q->endRemoveRows(); +// } else { // Could be a transient. +// // Removing a transient might change the demands attention state of the leader. +// if (transients.remove(window)) { +// if (PlasmaWindow *leader = transientsDemandingAttention.key(window)) { +// transientsDemandingAttention.remove(leader, window); +// dataChanged(leader, QVector{IsDemandingAttention}); +// } +// } +// } + +// if (activeWindow == window) { +// activeWindow = nullptr; +// } +// }; + +// QObject::connect(window, &PlasmaWindow::unmapped, q, removeWindow); + +// QObject::connect(window, &PlasmaWindow::titleChanged, q, [window, this] { +// this->dataChanged(window, Qt::DisplayRole); +// }); + +// QObject::connect(window, &PlasmaWindow::iconChanged, q, [window, this] { +// // The icon in the AppData struct might come from PlasmaWindow if it wasn't +// // filled in by windowUrlFromMetadata+appDataFromUrl. +// // TODO: Don't evict the cache unnecessarily if this isn't the case. As icons +// // are currently very static on Wayland, this eviction is unlikely to happen +// // frequently as of now. +// appDataCache.remove(window); +// this->dataChanged(window, Qt::DecorationRole); +// }); + +// QObject::connect(window, &PlasmaWindow::appIdChanged, q, [window, this] { +// // The AppData struct in the cache is derived from this and needs +// // to be evicted in favor of a fresh struct based on the changed +// // window metadata. +// appDataCache.remove(window); + +// // Refresh roles satisfied from the app data cache. +// this->dataChanged(window, +// QList{Qt::DecorationRole, AppId, AppName, GenericName, LauncherUrl, LauncherUrlWithoutIcon, SkipTaskbar, CanLaunchNewInstance}); +// }); + +// if (window->windowState & PlasmaWindow::state::state_active) { +// PlasmaWindow *effectiveActive = window; +// while (effectiveActive->parentWindow) { +// effectiveActive = effectiveActive->parentWindow; +// } + +// lastActivated[effectiveActive] = QTime::currentTime(); +// activeWindow = effectiveActive; +// } + +// QObject::connect(window, &PlasmaWindow::activeChanged, q, [window, this] { +// const bool active = window->windowState & PlasmaWindow::state::state_active; + +// PlasmaWindow *effectiveWindow = window; + +// while (effectiveWindow->parentWindow) { +// effectiveWindow = effectiveWindow->parentWindow; +// } + +// if (active) { +// lastActivated[effectiveWindow] = QTime::currentTime(); + +// if (activeWindow != effectiveWindow) { +// activeWindow = effectiveWindow; +// this->dataChanged(effectiveWindow, IsActive); +// } +// } else { +// if (activeWindow == effectiveWindow) { +// activeWindow = nullptr; +// this->dataChanged(effectiveWindow, IsActive); +// } +// } +// }); + +// QObject::connect(window, &PlasmaWindow::parentWindowChanged, q, [window, this] { +// PlasmaWindow *leader = window->parentWindow.data(); + +// // Migrate demanding attention to new leader. +// if (window->windowState.testFlag(PlasmaWindow::state::state_demands_attention)) { +// if (auto *oldLeader = transientsDemandingAttention.key(window)) { +// if (window->parentWindow != oldLeader) { +// transientsDemandingAttention.remove(oldLeader, window); +// transientsDemandingAttention.insert(leader, window); +// dataChanged(oldLeader, QVector{IsDemandingAttention}); +// dataChanged(leader, QVector{IsDemandingAttention}); +// } +// } +// } + +// if (transients.remove(window)) { +// if (leader) { // leader change. +// transients.insert(window, leader); +// } else { // lost a leader, add to regular windows list. +// Q_ASSERT(findWindow(window) == windows.end()); + +// const int count = windows.size(); +// q->beginInsertRows(QModelIndex(), count, count); +// windows.emplace_back(window); +// q->endInsertRows(); +// } +// } else if (leader) { // gained a leader, remove from regular windows list. +// auto it = findWindow(window); +// Q_ASSERT(it != windows.end()); + +// const int row = it - windows.begin(); +// q->beginRemoveRows(QModelIndex(), row, row); +// windows.erase(it); +// appDataCache.remove(window); +// lastActivated.remove(window); +// q->endRemoveRows(); +// } +// }); + +// QObject::connect(window, &PlasmaWindow::closeableChanged, q, [window, this] { +// this->dataChanged(window, IsClosable); +// }); + +// QObject::connect(window, &PlasmaWindow::movableChanged, q, [window, this] { +// this->dataChanged(window, IsMovable); +// }); + +// QObject::connect(window, &PlasmaWindow::resizableChanged, q, [window, this] { +// this->dataChanged(window, IsResizable); +// }); + +// QObject::connect(window, &PlasmaWindow::fullscreenableChanged, q, [window, this] { +// this->dataChanged(window, IsFullScreenable); +// }); + +// QObject::connect(window, &PlasmaWindow::fullscreenChanged, q, [window, this] { +// this->dataChanged(window, IsFullScreen); +// }); + +// QObject::connect(window, &PlasmaWindow::maximizeableChanged, q, [window, this] { +// this->dataChanged(window, IsMaximizable); +// }); + +// QObject::connect(window, &PlasmaWindow::maximizedChanged, q, [window, this] { +// this->dataChanged(window, IsMaximized); +// }); + +// QObject::connect(window, &PlasmaWindow::minimizeableChanged, q, [window, this] { +// this->dataChanged(window, IsMinimizable); +// }); + +// QObject::connect(window, &PlasmaWindow::minimizedChanged, q, [window, this] { +// this->dataChanged(window, IsMinimized); +// }); + +// QObject::connect(window, &PlasmaWindow::keepAboveChanged, q, [window, this] { +// this->dataChanged(window, IsKeepAbove); +// }); + +// QObject::connect(window, &PlasmaWindow::keepBelowChanged, q, [window, this] { +// this->dataChanged(window, IsKeepBelow); +// }); + +// QObject::connect(window, &PlasmaWindow::shadeableChanged, q, [window, this] { +// this->dataChanged(window, IsShadeable); +// }); + +// QObject::connect(window, &PlasmaWindow::virtualDesktopChangeableChanged, q, [window, this] { +// this->dataChanged(window, IsVirtualDesktopsChangeable); +// }); + +// QObject::connect(window, &PlasmaWindow::virtualDesktopEntered, q, [window, this] { +// this->dataChanged(window, VirtualDesktops); + +// // If the count has changed from 0, the window may no longer be on all virtual +// // desktops. +// if (window->virtualDesktops.count() > 0) { +// this->dataChanged(window, IsOnAllVirtualDesktops); +// } +// }); + +// QObject::connect(window, &PlasmaWindow::virtualDesktopLeft, q, [window, this] { +// this->dataChanged(window, VirtualDesktops); + +// // If the count has changed to 0, the window is now on all virtual desktops. +// if (window->virtualDesktops.count() == 0) { +// this->dataChanged(window, IsOnAllVirtualDesktops); +// } +// }); + +// QObject::connect(window, &PlasmaWindow::geometryChanged, q, [window, this] { +// this->dataChanged(window, QList{Geometry, ScreenGeometry}); +// }); + +// QObject::connect(window, &PlasmaWindow::demandsAttentionChanged, q, [window, this] { +// // Changes to a transient's state might change demands attention state for leader. +// if (auto *leader = transients.value(window)) { +// if (window->windowState.testFlag(PlasmaWindow::state::state_demands_attention)) { +// if (!transientsDemandingAttention.values(leader).contains(window)) { +// transientsDemandingAttention.insert(leader, window); +// this->dataChanged(leader, QVector{IsDemandingAttention}); +// } +// } else if (transientsDemandingAttention.remove(window)) { +// this->dataChanged(leader, QVector{IsDemandingAttention}); +// } +// } else { +// this->dataChanged(window, QVector{IsDemandingAttention}); +// } +// }); + +// QObject::connect(window, &PlasmaWindow::skipTaskbarChanged, q, [window, this] { +// this->dataChanged(window, SkipTaskbar); +// }); + +// QObject::connect(window, &PlasmaWindow::applicationMenuChanged, q, [window, this] { +// this->dataChanged(window, QList{ApplicationMenuServiceName, ApplicationMenuObjectPath}); +// }); + +// QObject::connect(window, &PlasmaWindow::activitiesChanged, q, [window, this] { +// this->dataChanged(window, Activities); +// }); + +// // Handle transient. +// if (PlasmaWindow *leader = window->parentWindow.data()) { +// transients.insert(window, leader); + +// // Update demands attention state for leader. +// if (window->windowState.testFlag(PlasmaWindow::state::state_demands_attention)) { +// transientsDemandingAttention.insert(leader, window); +// dataChanged(leader, QVector{IsDemandingAttention}); +// } +// } else { +// const int count = windows.size(); + +// q->beginInsertRows(QModelIndex(), count, count); + +// windows.emplace_back(window); + +// q->endInsertRows(); +// } +// } + +// const AppData &WaylandTasksModel::Private::appData(PlasmaWindow *window) +// { +// static_assert(!std::is_trivially_copy_assignable_v); +// if (auto it = appDataCache.constFind(window); it != appDataCache.constEnd()) { +// return *it; +// } + +// return *appDataCache.emplace(window, appDataFromUrl(windowUrlFromMetadata(window->appId, window->pid, rulesConfig, window->resourceName))); +// } + +// QIcon WaylandTasksModel::Private::icon(PlasmaWindow *window) +// { +// const AppData &app = appData(window); + +// if (!app.icon.isNull()) { +// return app.icon; +// } + +// appDataCache[window].icon = window->icon; + +// return window->icon; +// } + +// QString WaylandTasksModel::Private::mimeType() +// { +// // Use a unique format id to make this intentionally useless for +// // cross-process DND. +// return QStringLiteral("windowsystem/winid+") + uuid.toString(); +// } + +// QString WaylandTasksModel::Private::groupMimeType() +// { +// // Use a unique format id to make this intentionally useless for +// // cross-process DND. +// return QStringLiteral("windowsystem/multiple-winids+") + uuid.toString(); +// } + +// void WaylandTasksModel::Private::dataChanged(PlasmaWindow *window, int role) +// { +// auto it = findWindow(window); +// if (it == windows.end()) { +// return; +// } +// QModelIndex idx = q->index(it - windows.begin()); +// Q_EMIT q->dataChanged(idx, idx, QList{role}); +// } + +// void WaylandTasksModel::Private::dataChanged(PlasmaWindow *window, const QList &roles) +// { +// auto it = findWindow(window); +// if (it == windows.end()) { +// return; +// } +// QModelIndex idx = q->index(it - windows.begin()); +// Q_EMIT q->dataChanged(idx, idx, roles); +// } + +// WaylandTasksModel::WaylandTasksModel(QObject *parent) +// : AbstractWindowTasksModel(parent) +// , d(new Private(this)) +// { +// d->init(); +// } + +// WaylandTasksModel::~WaylandTasksModel() = default; + +// QVariant WaylandTasksModel::data(const QModelIndex &index, int role) const +// { +// // Note: when index is valid, its row >= 0, so casting to unsigned is safe +// if (!index.isValid() || static_cast(index.row()) >= d->windows.size()) { +// return QVariant(); +// } + +// PlasmaWindow *window = d->windows.at(index.row()).get(); + +// if (role == Qt::DisplayRole) { +// return window->title; +// } else if (role == Qt::DecorationRole) { +// return d->icon(window); +// } else if (role == AppId) { +// const QString &id = d->appData(window).id; + +// if (id.isEmpty()) { +// return window->appId; +// } else { +// return id; +// } +// } else if (role == AppName) { +// return d->appData(window).name; +// } else if (role == GenericName) { +// return d->appData(window).genericName; +// } else if (role == LauncherUrl || role == LauncherUrlWithoutIcon) { +// return d->appData(window).url; +// } else if (role == WinIdList) { +// return QVariantList{window->uuid}; +// } else if (role == MimeType) { +// return d->mimeType(); +// } else if (role == MimeData) { +// return window->uuid; +// } else if (role == IsWindow) { +// return true; +// } else if (role == IsActive) { +// return (window == d->activeWindow); +// } else if (role == IsClosable) { +// return window->windowState.testFlag(PlasmaWindow::state::state_closeable); +// } else if (role == IsMovable) { +// return window->windowState.testFlag(PlasmaWindow::state::state_movable); +// } else if (role == IsResizable) { +// return window->windowState.testFlag(PlasmaWindow::state::state_resizable); +// } else if (role == IsMaximizable) { +// return window->windowState.testFlag(PlasmaWindow::state::state_maximizable); +// } else if (role == IsMaximized) { +// return window->windowState.testFlag(PlasmaWindow::state::state_maximized); +// } else if (role == IsMinimizable) { +// return window->windowState.testFlag(PlasmaWindow::state::state_minimizable); +// } else if (role == IsMinimized || role == IsHidden) { +// return window->windowState.testFlag(PlasmaWindow::state::state_minimized); +// } else if (role == IsKeepAbove) { +// return window->windowState.testFlag(PlasmaWindow::state::state_keep_above); +// } else if (role == IsKeepBelow) { +// return window->windowState.testFlag(PlasmaWindow::state::state_keep_below); +// } else if (role == IsFullScreenable) { +// return window->windowState.testFlag(PlasmaWindow::state::state_fullscreenable); +// } else if (role == IsFullScreen) { +// return window->windowState.testFlag(PlasmaWindow::state::state_fullscreen); +// } else if (role == IsShadeable) { +// return window->windowState.testFlag(PlasmaWindow::state::state_shadeable); +// } else if (role == IsShaded) { +// return window->windowState.testFlag(PlasmaWindow::state::state_shaded); +// } else if (role == IsVirtualDesktopsChangeable) { +// return window->windowState.testFlag(PlasmaWindow::state::state_virtual_desktop_changeable); +// } else if (role == VirtualDesktops) { +// return window->virtualDesktops; +// } else if (role == IsOnAllVirtualDesktops) { +// return window->virtualDesktops.isEmpty(); +// } else if (role == Geometry) { +// return window->geometry; +// } else if (role == ScreenGeometry) { +// return screenGeometry(window->geometry.center()); +// } else if (role == Activities) { +// return window->activities; +// } else if (role == IsDemandingAttention) { +// return window->windowState.testFlag(PlasmaWindow::state::state_demands_attention) || d->transientsDemandingAttention.contains(window); +// } else if (role == SkipTaskbar) { +// return window->windowState.testFlag(PlasmaWindow::state::state_skiptaskbar) || d->appData(window).skipTaskbar; +// } else if (role == SkipPager) { +// // FIXME Implement. +// } else if (role == AppPid) { +// return window->pid; +// } else if (role == StackingOrder) { +// return d->stackingOrder.indexOf(window->uuid); +// } else if (role == LastActivated) { +// if (d->lastActivated.contains(window)) { +// return d->lastActivated.value(window); +// } +// } else if (role == ApplicationMenuObjectPath) { +// return window->applicationMenuObjectPath; +// } else if (role == ApplicationMenuServiceName) { +// return window->applicationMenuService; +// } else if (role == CanLaunchNewInstance) { +// return canLauchNewInstance(d->appData(window)); +// } + +// return AbstractTasksModel::data(index, role); +// } + +// int WaylandTasksModel::rowCount(const QModelIndex &parent) const +// { +// return parent.isValid() ? 0 : d->windows.size(); +// } + +// QModelIndex WaylandTasksModel::index(int row, int column, const QModelIndex &parent) const +// { +// return hasIndex(row, column, parent) ? createIndex(row, column, d->windows.at(row).get()) : QModelIndex(); +// } + +// void WaylandTasksModel::requestActivate(const QModelIndex &index) +// { +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) { +// return; +// } + +// PlasmaWindow *window = d->windows.at(index.row()).get(); + +// // Pull forward any transient demanding attention. +// if (auto *transientDemandingAttention = d->transientsDemandingAttention.value(window)) { +// window = transientDemandingAttention; +// } else { +// // TODO Shouldn't KWin take care of that? +// // Bringing a transient to the front usually brings its parent with it +// // but focus is not handled properly. +// // TODO take into account d->lastActivation instead +// // of just taking the first one. +// while (d->transients.key(window)) { +// window = d->transients.key(window); +// } +// } + +// window->set_state(PlasmaWindow::state::state_active, PlasmaWindow::state::state_active); +// } + +// void WaylandTasksModel::requestNewInstance(const QModelIndex &index) +// { +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) { +// return; +// } + +// runApp(d->appData(d->windows.at(index.row()).get())); +// } + +// void WaylandTasksModel::requestOpenUrls(const QModelIndex &index, const QList &urls) +// { +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent) || urls.isEmpty()) { +// return; +// } + +// runApp(d->appData(d->windows.at(index.row()).get()), urls); +// } + +// void WaylandTasksModel::requestClose(const QModelIndex &index) +// { +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) { +// return; +// } + +// d->windows.at(index.row())->close(); +// } + +// void WaylandTasksModel::requestMove(const QModelIndex &index) +// { +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) { +// return; +// } + +// auto &window = d->windows.at(index.row()); + +// window->set_state(PlasmaWindow::state::state_active, PlasmaWindow::state::state_active); +// window->request_move(); +// } + +// void WaylandTasksModel::requestResize(const QModelIndex &index) +// { +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) { +// return; +// } + +// auto &window = d->windows.at(index.row()); + +// window->set_state(PlasmaWindow::state::state_active, PlasmaWindow::state::state_active); +// window->request_resize(); +// } + +// void WaylandTasksModel::requestToggleMinimized(const QModelIndex &index) +// { +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) { +// return; +// } + +// auto &window = d->windows.at(index.row()); + +// if (window->windowState & PlasmaWindow::state::state_minimized) { +// window->set_state(PlasmaWindow::state::state_minimized, 0); +// } else { +// window->set_state(PlasmaWindow::state::state_minimized, PlasmaWindow::state::state_minimized); +// } +// } + +// void WaylandTasksModel::requestToggleMaximized(const QModelIndex &index) +// { +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) { +// return; +// } + +// auto &window = d->windows.at(index.row()); + +// if (window->windowState & PlasmaWindow::state::state_maximized) { +// window->set_state(PlasmaWindow::state::state_maximized | PlasmaWindow::state::state_active, PlasmaWindow::state::state_active); +// } else { +// window->set_state(PlasmaWindow::state::state_maximized | PlasmaWindow::state::state_active, +// PlasmaWindow::state::state_maximized | PlasmaWindow::state::state_active); +// } +// } + +// void WaylandTasksModel::requestToggleKeepAbove(const QModelIndex &index) +// { +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) { +// return; +// } + +// auto &window = d->windows.at(index.row()); + +// if (window->windowState & PlasmaWindow::state::state_keep_above) { +// window->set_state(PlasmaWindow::state::state_keep_above, 0); +// } else { +// window->set_state(PlasmaWindow::state::state_keep_above, PlasmaWindow::state::state_keep_above); +// } +// } + +// void WaylandTasksModel::requestToggleKeepBelow(const QModelIndex &index) +// { +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) { +// return; +// } +// auto &window = d->windows.at(index.row()); + +// if (window->windowState & PlasmaWindow::state::state_keep_below) { +// window->set_state(PlasmaWindow::state::state_keep_below, 0); +// } else { +// window->set_state(PlasmaWindow::state::state_keep_below, PlasmaWindow::state::state_keep_below); +// } +// } + +// void WaylandTasksModel::requestToggleFullScreen(const QModelIndex &index) +// { +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) { +// return; +// } + +// auto &window = d->windows.at(index.row()); + +// if (window->windowState & PlasmaWindow::state::state_fullscreen) { +// window->set_state(PlasmaWindow::state::state_fullscreen, 0); +// } else { +// window->set_state(PlasmaWindow::state::state_fullscreen, PlasmaWindow::state::state_fullscreen); +// } +// } + +// void WaylandTasksModel::requestToggleShaded(const QModelIndex &index) +// { +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) { +// return; +// } + +// auto &window = d->windows.at(index.row()); + +// if (window->windowState & PlasmaWindow::state::state_shaded) { +// window->set_state(PlasmaWindow::state::state_shaded, 0); +// } else { +// window->set_state(PlasmaWindow::state::state_shaded, PlasmaWindow::state::state_shaded); +// }; +// } + +// void WaylandTasksModel::requestVirtualDesktops(const QModelIndex &index, const QVariantList &desktops) +// { +// // FIXME TODO: Lacks the "if we've requested the current desktop, force-activate +// // the window" logic from X11 version. This behavior should be in KWin rather than +// // libtm however. + +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) { +// return; +// } + +// auto &window = d->windows.at(index.row()); + +// if (desktops.isEmpty()) { +// const QStringList virtualDesktops = window->virtualDesktops; +// for (const QString &desktop : virtualDesktops) { +// window->request_leave_virtual_desktop(desktop); +// } +// } else { +// const QStringList &now = window->virtualDesktops; +// QStringList next; + +// for (const QVariant &desktop : desktops) { +// const QString &desktopId = desktop.toString(); + +// if (!desktopId.isEmpty()) { +// next << desktopId; + +// if (!now.contains(desktopId)) { +// window->request_enter_virtual_desktop(desktopId); +// } +// } +// } + +// for (const QString &desktop : now) { +// if (!next.contains(desktop)) { +// window->request_leave_virtual_desktop(desktop); +// } +// } +// } +// } + +// void WaylandTasksModel::requestNewVirtualDesktop(const QModelIndex &index) +// { +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) { +// return; +// } + +// d->windows.at(index.row())->request_enter_new_virtual_desktop(); +// } + +// void WaylandTasksModel::requestActivities(const QModelIndex &index, const QStringList &activities) +// { +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) { +// return; +// } + +// auto &window = d->windows.at(index.row()); +// const auto newActivities = QSet(activities.begin(), activities.end()); +// const auto plasmaActivities = window->activities; +// const auto oldActivities = QSet(plasmaActivities.begin(), plasmaActivities.end()); + +// const auto activitiesToAdd = newActivities - oldActivities; +// for (const auto &activity : activitiesToAdd) { +// window->request_enter_activity(activity); +// } + +// const auto activitiesToRemove = oldActivities - newActivities; +// for (const auto &activity : activitiesToRemove) { +// window->request_leave_activity(activity); +// } +// } + +// void WaylandTasksModel::requestPublishDelegateGeometry(const QModelIndex &index, const QRect &geometry, QObject *delegate) +// { +// /* +// FIXME: This introduces the dependency on Qt::Quick. I might prefer +// reversing this and publishing the window pointer through the model, +// then calling PlasmaWindow::setMinimizeGeometry in the applet backend, +// rather than hand delegate items into the lib, keeping the lib more UI- +// agnostic. +// */ + +// Q_UNUSED(geometry) + +// if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) { +// return; +// } + +// const QQuickItem *item = qobject_cast(delegate); + +// if (!item || !item->parentItem()) { +// return; +// } + +// QWindow *itemWindow = item->window(); + +// if (!itemWindow) { +// return; +// } + +// auto waylandWindow = itemWindow->nativeInterface(); + +// if (!waylandWindow || !waylandWindow->surface()) { +// return; +// } + +// QRect rect(item->x(), item->y(), item->width(), item->height()); +// rect.moveTopLeft(item->parentItem()->mapToScene(rect.topLeft()).toPoint()); + +// auto &window = d->windows.at(index.row()); + +// window->set_minimized_geometry(waylandWindow->surface(), rect.x(), rect.y(), rect.width(), rect.height()); +// } + +// QUuid WaylandTasksModel::winIdFromMimeData(const QMimeData *mimeData, bool *ok) +// { +// Q_ASSERT(mimeData); + +// if (ok) { +// *ok = false; +// } + +// if (!mimeData->hasFormat(Private::mimeType())) { +// return {}; +// } + +// QUuid id(mimeData->data(Private::mimeType())); +// *ok = !id.isNull(); + +// return id; +// } + +// QList WaylandTasksModel::winIdsFromMimeData(const QMimeData *mimeData, bool *ok) +// { +// Q_ASSERT(mimeData); +// QList ids; + +// if (ok) { +// *ok = false; +// } + +// if (!mimeData->hasFormat(Private::groupMimeType())) { +// // Try to extract single window id. +// bool singularOk; +// QUuid id = winIdFromMimeData(mimeData, &singularOk); + +// if (ok) { +// *ok = singularOk; +// } + +// if (singularOk) { +// ids << id; +// } + +// return ids; +// } + +// // FIXME: Extracting multiple winids is still unimplemented; +// // TaskGroupingProxy::data(..., ::MimeData) can't produce +// // a payload with them anyways. + +// return ids; +// } + +LXQtTaskBarPlasmaWindow::LXQtTaskBarPlasmaWindow(const QString &uuid, ::org_kde_plasma_window *id) + : org_kde_plasma_window(id) + , uuid(uuid) +{ +} + +/* + * LXQtTaskBarPlasmaWindow + */ + +LXQtTaskBarPlasmaWindow::~LXQtTaskBarPlasmaWindow() +{ + destroy(); +} + +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_unmapped() +{ + wasUnmapped = true; + Q_EMIT unmapped(); +} + +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_title_changed(const QString &title) +{ + if(this->title == title) + return; + this->title = title; + Q_EMIT titleChanged(); +} + +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_app_id_changed(const QString &app_id) +{ + if(appId == app_id) + return; + appId = app_id; + Q_EMIT appIdChanged(); +} + +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_icon_changed() +{ + int pipeFds[2]; + if (pipe2(pipeFds, O_CLOEXEC) != 0) { + qWarning() << "TaskManager: failed creating pipe"; + return; + } + get_icon(pipeFds[1]); + ::close(pipeFds[1]); + auto readIcon = [uuid = uuid](int fd) { + auto closeGuard = qScopeGuard([fd]() { + ::close(fd); + }); + pollfd pollFd; + pollFd.fd = fd; + pollFd.events = POLLIN; + QByteArray data; + while (true) { + int ready = poll(&pollFd, 1, 1000); + if (ready < 0 && errno != EINTR) { + qWarning() << "TaskManager: polling for icon of window" << uuid << "failed"; + return QIcon(); + } else if (ready == 0) { + qWarning() << "TaskManager: time out polling for icon of window" << uuid; + return QIcon(); + } else { + char buffer[4096]; + int n = read(fd, buffer, sizeof(buffer)); + if (n < 0) { + qWarning() << "TaskManager: error reading icon of window" << uuid; + return QIcon(); + } else if (n > 0) { + data.append(buffer, n); + } else { + QIcon icon; + QDataStream ds(data); + ds >> icon; + return icon; + } + } + } + }; + QFuture future = QtConcurrent::run(readIcon, pipeFds[0]); + auto watcher = new QFutureWatcher(); + watcher->setFuture(future); + connect(watcher, &QFutureWatcher::finished, this, [this, watcher] { + icon = watcher->future().result(); + Q_EMIT iconChanged(); + }); + connect(watcher, &QFutureWatcher::finished, watcher, &QObject::deleteLater); +} + +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_themed_icon_name_changed(const QString &name) +{ + icon = QIcon::fromTheme(name); + Q_EMIT iconChanged(); +} + +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_state_changed(uint32_t flags) +{ + auto diff = windowState ^ flags; + if (diff & state::state_active) { + windowState.setFlag(state::state_active, flags & state::state_active); + Q_EMIT activeChanged(); + } + if (diff & state::state_minimized) { + windowState.setFlag(state::state_minimized, flags & state::state_minimized); + Q_EMIT minimizedChanged(); + } + if (diff & state::state_maximized) { + windowState.setFlag(state::state_maximized, flags & state::state_maximized); + Q_EMIT maximizedChanged(); + } + if (diff & state::state_fullscreen) { + windowState.setFlag(state::state_fullscreen, flags & state::state_fullscreen); + Q_EMIT fullscreenChanged(); + } + if (diff & state::state_keep_above) { + windowState.setFlag(state::state_keep_above, flags & state::state_keep_above); + Q_EMIT keepAboveChanged(); + } + if (diff & state::state_keep_below) { + windowState.setFlag(state::state_keep_below, flags & state::state_keep_below); + Q_EMIT keepBelowChanged(); + } + if (diff & state::state_on_all_desktops) { + windowState.setFlag(state::state_on_all_desktops, flags & state::state_on_all_desktops); + Q_EMIT onAllDesktopsChanged(); + } + if (diff & state::state_demands_attention) { + windowState.setFlag(state::state_demands_attention, flags & state::state_demands_attention); + Q_EMIT demandsAttentionChanged(); + } + if (diff & state::state_closeable) { + windowState.setFlag(state::state_closeable, flags & state::state_closeable); + Q_EMIT closeableChanged(); + } + if (diff & state::state_minimizable) { + windowState.setFlag(state::state_minimizable, flags & state::state_minimizable); + Q_EMIT minimizeableChanged(); + } + if (diff & state::state_maximizable) { + windowState.setFlag(state::state_maximizable, flags & state::state_maximizable); + Q_EMIT maximizeableChanged(); + } + if (diff & state::state_fullscreenable) { + windowState.setFlag(state::state_fullscreenable, flags & state::state_fullscreenable); + Q_EMIT fullscreenableChanged(); + } + if (diff & state::state_skiptaskbar) { + windowState.setFlag(state::state_skiptaskbar, flags & state::state_skiptaskbar); + Q_EMIT skipTaskbarChanged(); + } + if (diff & state::state_shadeable) { + windowState.setFlag(state::state_shadeable, flags & state::state_shadeable); + Q_EMIT shadeableChanged(); + } + if (diff & state::state_shaded) { + windowState.setFlag(state::state_shaded, flags & state::state_shaded); + Q_EMIT shadedChanged(); + } + if (diff & state::state_movable) { + windowState.setFlag(state::state_movable, flags & state::state_movable); + Q_EMIT movableChanged(); + } + if (diff & state::state_resizable) { + windowState.setFlag(state::state_resizable, flags & state::state_resizable); + Q_EMIT resizableChanged(); + } + if (diff & state::state_virtual_desktop_changeable) { + windowState.setFlag(state::state_virtual_desktop_changeable, flags & state::state_virtual_desktop_changeable); + Q_EMIT virtualDesktopChangeableChanged(); + } + if (diff & state::state_skipswitcher) { + windowState.setFlag(state::state_skipswitcher, flags & state::state_skipswitcher); + Q_EMIT skipSwitcherChanged(); + } +} + +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_virtual_desktop_entered(const QString &id) +{ + virtualDesktops.push_back(id); + Q_EMIT virtualDesktopEntered(); +} + +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_virtual_desktop_left(const QString &id) +{ + virtualDesktops.removeAll(id); + Q_EMIT virtualDesktopLeft(); +} + +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_geometry(int32_t x, int32_t y, uint32_t width, uint32_t height) +{ + geometry = QRect(x, y, width, height); + Q_EMIT geometryChanged(); +} + +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_application_menu(const QString &service_name, const QString &object_path) +{ + applicationMenuService = service_name; + applicationMenuObjectPath = object_path; + Q_EMIT applicationMenuChanged(); +} + +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_activity_entered(const QString &id) +{ + activities.push_back(id); + Q_EMIT activitiesChanged(); +} +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_activity_left(const QString &id) +{ + activities.removeAll(id); + Q_EMIT activitiesChanged(); +} +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_pid_changed(uint32_t pid) +{ + this->pid = pid; +} +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_resource_name_changed(const QString &resource_name) +{ + resourceName = resource_name; +} +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_parent_window(::org_kde_plasma_window *parent) +{ + LXQtTaskBarPlasmaWindow *parentWindow = nullptr; + if (parent) { + parentWindow = dynamic_cast(LXQtTaskBarPlasmaWindow::fromObject(parent)); + } + setParentWindow(parentWindow); +} +void LXQtTaskBarPlasmaWindow::org_kde_plasma_window_initial_state() +{ + Q_EMIT initialStateDone(); +} + +void LXQtTaskBarPlasmaWindow::setParentWindow(LXQtTaskBarPlasmaWindow *parent) +{ + const auto old = parentWindow; + QObject::disconnect(parentWindowUnmappedConnection); + + if (parent && !parent->wasUnmapped) { + parentWindow = QPointer(parent); + parentWindowUnmappedConnection = QObject::connect(parent, &LXQtTaskBarPlasmaWindow::unmapped, this, [this] { + setParentWindow(nullptr); + }); + } else { + parentWindow = QPointer(); + parentWindowUnmappedConnection = QMetaObject::Connection(); + } + + if (parentWindow.data() != old.data()) { + Q_EMIT parentWindowChanged(); + } +} + +/* + * LXQtTaskBarPlasmaWindowManagment + */ + +LXQtTaskBarPlasmaWindowManagment::LXQtTaskBarPlasmaWindowManagment() + : QWaylandClientExtensionTemplate(version) +{ + connect(this, &QWaylandClientExtension::activeChanged, this, [this] { + if (!isActive()) { + wl_proxy_destroy(reinterpret_cast(object())); + } + }); +} + +LXQtTaskBarPlasmaWindowManagment::~LXQtTaskBarPlasmaWindowManagment() +{ + if (isActive()) { + wl_proxy_destroy(reinterpret_cast(object())); + } +} + +void LXQtTaskBarPlasmaWindowManagment::org_kde_plasma_window_management_window_with_uuid(uint32_t id, const QString &uuid) +{ + Q_UNUSED(id) + Q_EMIT windowCreated(new LXQtTaskBarPlasmaWindow(uuid, get_window_by_uuid(uuid))); +} +void LXQtTaskBarPlasmaWindowManagment::org_kde_plasma_window_management_stacking_order_uuid_changed(const QString &uuids) +{ + Q_EMIT stackingOrderChanged(uuids); +} diff --git a/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.h b/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.h new file mode 100644 index 000000000..78c75693d --- /dev/null +++ b/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.h @@ -0,0 +1,154 @@ +#ifndef LXQTTASKBARPLASMAWINDOWMANAGMENT_H +#define LXQTTASKBARPLASMAWINDOWMANAGMENT_H + +#include +#include +#include + +#include "qwayland-plasma-window-management.h" + +typedef quintptr WId; + +class LXQtTaskBarPlasmaWindowManagment; + +class LXQtTaskBarPlasmaWindow : public QObject, + public QtWayland::org_kde_plasma_window +{ + Q_OBJECT +public: + LXQtTaskBarPlasmaWindow(const QString &uuid, ::org_kde_plasma_window *id); + ~LXQtTaskBarPlasmaWindow(); + + inline WId getWindowId() const { return reinterpret_cast(this); } + + using state = QtWayland::org_kde_plasma_window_management::state; + const QString uuid; + QString title; + QString appId; + QIcon icon; + QFlags windowState; + QList virtualDesktops; + QRect geometry; + QString applicationMenuService; + QString applicationMenuObjectPath; + QList activities; + quint32 pid; + QString resourceName; + QPointer parentWindow; + bool wasUnmapped = false; + bool acceptedInTaskBar = false; + +Q_SIGNALS: + void unmapped(); + void titleChanged(); + void appIdChanged(); + void iconChanged(); + void activeChanged(); + void minimizedChanged(); + void maximizedChanged(); + void fullscreenChanged(); + void keepAboveChanged(); + void keepBelowChanged(); + void onAllDesktopsChanged(); + void demandsAttentionChanged(); + void closeableChanged(); + void minimizeableChanged(); + void maximizeableChanged(); + void fullscreenableChanged(); + void skiptaskbarChanged(); + void shadeableChanged(); + void shadedChanged(); + void movableChanged(); + void resizableChanged(); + void virtualDesktopChangeableChanged(); + void skipSwitcherChanged(); + void virtualDesktopEntered(); + void virtualDesktopLeft(); + void geometryChanged(); + void skipTaskbarChanged(); + void applicationMenuChanged(); + void activitiesChanged(); + void parentWindowChanged(); + void initialStateDone(); + +protected: + void org_kde_plasma_window_unmapped() override; + void org_kde_plasma_window_title_changed(const QString &title) override; + void org_kde_plasma_window_app_id_changed(const QString &app_id) override; + void org_kde_plasma_window_icon_changed() override; + void org_kde_plasma_window_themed_icon_name_changed(const QString &name) override; + void org_kde_plasma_window_state_changed(uint32_t flags) override; + void org_kde_plasma_window_virtual_desktop_entered(const QString &id) override; + + void org_kde_plasma_window_virtual_desktop_left(const QString &id) override; + void org_kde_plasma_window_geometry(int32_t x, int32_t y, uint32_t width, uint32_t height) override; + void org_kde_plasma_window_application_menu(const QString &service_name, const QString &object_path) override; + void org_kde_plasma_window_activity_entered(const QString &id) override; + void org_kde_plasma_window_activity_left(const QString &id) override; + void org_kde_plasma_window_pid_changed(uint32_t pid) override; + void org_kde_plasma_window_resource_name_changed(const QString &resource_name) override; + void org_kde_plasma_window_parent_window(::org_kde_plasma_window *parent) override; + void org_kde_plasma_window_initial_state() override; + +private: + void setParentWindow(LXQtTaskBarPlasmaWindow *parent); + + QMetaObject::Connection parentWindowUnmappedConnection; +}; + +class LXQtTaskBarPlasmaWindowManagment : public QWaylandClientExtensionTemplate, + public QtWayland::org_kde_plasma_window_management +{ + Q_OBJECT +public: + static constexpr int version = 16; + LXQtTaskBarPlasmaWindowManagment(); + ~LXQtTaskBarPlasmaWindowManagment(); + + void org_kde_plasma_window_management_window_with_uuid(uint32_t id, const QString &uuid) override; + void org_kde_plasma_window_management_stacking_order_uuid_changed(const QString &uuids) override; + +Q_SIGNALS: + void windowCreated(LXQtTaskBarPlasmaWindow *window); + void stackingOrderChanged(const QString &uuids); +}; + +// class Q_DECL_HIDDEN WaylandTasksModel::Private +// { +// public: +// Private(WaylandTasksModel *q); +// QHash appDataCache; +// QHash lastActivated; +// PlasmaWindow *activeWindow = nullptr; +// std::vector> windows; +// // key=transient child, value=leader +// QHash transients; +// // key=leader, values=transient children +// QMultiHash transientsDemandingAttention; +// std::unique_ptr windowManagement; +// KSharedConfig::Ptr rulesConfig; +// KDirWatch *configWatcher = nullptr; +// VirtualDesktopInfo *virtualDesktopInfo = nullptr; +// static QUuid uuid; +// QList stackingOrder; + +// void init(); +// void initWayland(); +// auto findWindow(PlasmaWindow *window) const; +// void addWindow(PlasmaWindow *window); + +// const AppData &appData(PlasmaWindow *window); + +// QIcon icon(PlasmaWindow *window); + +// static QString mimeType(); +// static QString groupMimeType(); + +// void dataChanged(PlasmaWindow *window, int role); +// void dataChanged(PlasmaWindow *window, const QList &roles); + +// private: +// WaylandTasksModel *q; +// }; + +#endif // LXQTTASKBARPLASMAWINDOWMANAGMENT_H diff --git a/panel/backends/wayland/protocols/plasma-window-management.xml b/panel/backends/wayland/protocols/plasma-window-management.xml new file mode 100644 index 000000000..5990ebfda --- /dev/null +++ b/panel/backends/wayland/protocols/plasma-window-management.xml @@ -0,0 +1,425 @@ + + + + + + + This interface manages application windows. + It provides requests to show and hide the desktop and emits + an event every time a window is created so that the client can + use it to manage the window. + + Only one client can bind this interface at a time. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tell the compositor to show/hide the desktop. + + + + + + Deprecated: use get_window_by_uuid + + + + + + + + + + + + This event will be sent whenever the show desktop mode changes. E.g. when it is entered + or left. + + On binding the interface the current state is sent. + + + + + + + This event will be sent immediately after a window is mapped. + + + + + + + This event will be sent when stacking order changed and on bind + + + + + + + This event will be sent when stacking order changed and on bind + + + + + + + This event will be sent immediately after a window is mapped. + + + + + + + + + Manages and control an application window. + + Only one client can bind this interface at a time. + + + + + Set window state. + + Values for state argument are described by org_kde_plasma_window_management.state + and can be used together in a bitfield. The flags bitfield describes which flags are + supposed to be set, the state bitfield the value for the set flags + + + + + + + + Deprecated: use enter_virtual_desktop + Maps the window to a different virtual desktop. + + To show the window on all virtual desktops, call the + org_kde_plasma_window.set_state request and specify a on_all_desktops + state in the bitfield. + + + + + + + Sets the geometry of the taskbar entry for this window. + The geometry is relative to a panel in particular. + + + + + + + + + + + Remove the task geometry information for a particular panel. + + + + + + + + + Close this window. + + + + + + Request an interactive move for this window. + + + + + + Request an interactive resize for this window. + + + + + + Removes the resource bound for this org_kde_plasma_window. + + + + + + The compositor will write the window icon into the provided file descriptor. + The data is a serialized QIcon with QDataStream. + + + + + + + This event will be sent as soon as the window title is changed. + + + + + + + This event will be sent as soon as the application + identifier is changed. + + + + + + + This event will be sent as soon as the window state changes. + + Values for state argument are described by org_kde_plasma_window_management.state. + + + + + + + DEPRECATED: use virtual_desktop_entered and virtual_desktop_left instead + This event will be sent when a window is moved to another + virtual desktop. + + It is not sent if it becomes visible on all virtual desktops though. + + + + + + + This event will be sent whenever the themed icon name changes. May be null. + + + + + + + This event will be sent immediately after the window is closed + and its surface is unmapped. + + + + + + This event will be sent immediately after all initial state been sent to the client. + If the Plasma window is already unmapped, the unmapped event will be sent before the + initial_state event. + + + + + + This event will be sent whenever the parent window of this org_kde_plasma_window changes. + The passed parent is another org_kde_plasma_window and this org_kde_plasma_window is a + transient window to the parent window. If the parent argument is null, this + org_kde_plasma_window does not have a parent window. + + + + + + + This event will be sent whenever the window geometry of this org_kde_plasma_window changes. + The coordinates are in absolute coordinates of the windowing system. + + + + + + + + + + This event will be sent whenever the icon of the window changes, but there is no themed + icon name. Common examples are Xwayland windows which have a pixmap based icon. + + The client can request the icon using get_icon. + + + + + + This event will be sent when the compositor has set the process id this window belongs to. + This should be set once before the initial_state is sent. + + + + + + + + + + Make the window enter a virtual desktop. A window can enter more + than one virtual desktop. if the id is empty or invalid, no action will be performed. + + + + + + RFC: do this with an empty id to request_enter_virtual_desktop? + Make the window enter a new virtual desktop. If the server consents the request, + it will create a new virtual desktop and assign the window to it. + + + + + + Make the window exit a virtual desktop. If it exits all desktops it will be considered on all of them. + + + + + + + This event will be sent when the window has entered a new virtual desktop. The window can be on more than one desktop, or none: then is considered on all of them. + + + + + + + This event will be sent when the window left a virtual desktop. If the window leaves all desktops, it can be considered on all. + If the window gets manually added on all desktops, the server has to send virtual_desktop_left for every previous desktop it was in for the window to be really considered on all desktops. + + + + + + + + + This event will be sent after the application menu + for the window has changed. + + + + + + + + Make the window enter an activity. A window can enter more activity. If the id is empty or invalid, no action will be performed. + + + + + + + Make the window exit a an activity. If it exits all activities it will be considered on all of them. + + + + + + + This event will be sent when the window has entered an activity. The window can be on more than one activity, or none: then is considered on all of them. + + + + + + + This event will be sent when the window left an activity. If the window leaves all activities, it will be considered on all. + If the window gets manually added on all activities, the server has to send activity_left for every previous activity it was in for the window to be really considered on all activities. + + + + + + + Requests this window to be displayed in a specific output. + + + + + + + This event will be sent when the X11 resource name of the window has changed. + This is only set for XWayland windows. + + + + + + + + The activation manager interface provides a way to get notified + when an application is about to be activated. + + + + + Destroy the activation manager object. The activation objects introduced + by this manager object will be unaffected. + + + + + + Will be issued when an app is set to be activated. It offers + an instance of org_kde_plasma_activation that will tell us the app_id + and the extent of the activation. + + + + + + + + + Notify the compositor that the org_kde_plasma_activation object will no + longer be used. + + + + + + + + + + + + + diff --git a/panel/lxqtpanelapplication.cpp b/panel/lxqtpanelapplication.cpp index c3b666620..507163221 100644 --- a/panel/lxqtpanelapplication.cpp +++ b/panel/lxqtpanelapplication.cpp @@ -40,11 +40,14 @@ #include "backends/lxqttaskbardummybackend.h" #include "backends/xcb/lxqttaskbarbackend_x11.h" +#include "backends/wayland/lxqttaskbarbackendwayland.h" ILXQtTaskbarAbstractBackend *createWMBackend() { if(qGuiApp->nativeInterface()) return new LXQtTaskbarX11Backend; + else if(qGuiApp->nativeInterface()) + return new LXQtTaskbarWaylandBackend; qWarning() << "\n" << "ERROR: Could not create a backend for window managment operations.\n" From 575ba5dfbda76e95f4e4e3c27f92edf0e0829d3c Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Thu, 22 Feb 2024 17:12:45 +0100 Subject: [PATCH 71/92] LXQtTaskBarPlasmaWindowManagment: implement showDesktop() --- .../wayland/lxqttaskbarbackendwayland.cpp | 17 +++++++++++++++++ .../wayland/lxqttaskbarbackendwayland.h | 4 ++++ .../lxqttaskbarplasmawindowmanagment.cpp | 5 +++++ .../wayland/lxqttaskbarplasmawindowmanagment.h | 7 +++++++ 4 files changed, 33 insertions(+) diff --git a/panel/backends/wayland/lxqttaskbarbackendwayland.cpp b/panel/backends/wayland/lxqttaskbarbackendwayland.cpp index a2a415504..d85ec99d8 100644 --- a/panel/backends/wayland/lxqttaskbarbackendwayland.cpp +++ b/panel/backends/wayland/lxqttaskbarbackendwayland.cpp @@ -372,6 +372,23 @@ bool LXQtTaskbarWaylandBackend::isAreaOverlapped(const QRect &area) const return false; } +bool LXQtTaskbarWaylandBackend::isShowingDesktop() const +{ + return m_managment->isShowingDesktop(); +} + +bool LXQtTaskbarWaylandBackend::showDesktop(bool value) +{ + enum LXQtTaskBarPlasmaWindowManagment::show_desktop flag_; + if(value) + flag_ = LXQtTaskBarPlasmaWindowManagment::show_desktop::show_desktop_enabled; + else + flag_ = LXQtTaskBarPlasmaWindowManagment::show_desktop::show_desktop_disabled; + + m_managment->show_desktop(flag_); + return true; +} + void LXQtTaskbarWaylandBackend::addWindow(LXQtTaskBarPlasmaWindow *window) { if (findWindow(windows, window) != windows.end() || transients.contains(window)) diff --git a/panel/backends/wayland/lxqttaskbarbackendwayland.h b/panel/backends/wayland/lxqttaskbarbackendwayland.h index 553a7e585..77d857eb9 100644 --- a/panel/backends/wayland/lxqttaskbarbackendwayland.h +++ b/panel/backends/wayland/lxqttaskbarbackendwayland.h @@ -65,6 +65,10 @@ class LXQtTaskbarWaylandBackend : public ILXQtTaskbarAbstractBackend // Panel internal virtual bool isAreaOverlapped(const QRect& area) const override; + // Show Destop + virtual bool isShowingDesktop() const override; + virtual bool showDesktop(bool value) override; + private: void addWindow(LXQtTaskBarPlasmaWindow *window); bool acceptWindow(LXQtTaskBarPlasmaWindow *window) const; diff --git a/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp b/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp index 0a282eadd..3b765d3b3 100644 --- a/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp +++ b/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp @@ -1135,6 +1135,11 @@ LXQtTaskBarPlasmaWindowManagment::~LXQtTaskBarPlasmaWindowManagment() } } +void LXQtTaskBarPlasmaWindowManagment::org_kde_plasma_window_management_show_desktop_changed(uint32_t state) +{ + m_isShowingDesktop = (state == show_desktop::show_desktop_enabled); +} + void LXQtTaskBarPlasmaWindowManagment::org_kde_plasma_window_management_window_with_uuid(uint32_t id, const QString &uuid) { Q_UNUSED(id) diff --git a/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.h b/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.h index 78c75693d..c21b57b3c 100644 --- a/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.h +++ b/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.h @@ -105,12 +105,19 @@ class LXQtTaskBarPlasmaWindowManagment : public QWaylandClientExtensionTemplate< LXQtTaskBarPlasmaWindowManagment(); ~LXQtTaskBarPlasmaWindowManagment(); + inline bool isShowingDesktop() const { return m_isShowingDesktop; } + +protected: + void org_kde_plasma_window_management_show_desktop_changed(uint32_t state) override; void org_kde_plasma_window_management_window_with_uuid(uint32_t id, const QString &uuid) override; void org_kde_plasma_window_management_stacking_order_uuid_changed(const QString &uuids) override; Q_SIGNALS: void windowCreated(LXQtTaskBarPlasmaWindow *window); void stackingOrderChanged(const QString &uuids); + +private: + bool m_isShowingDesktop = false; }; // class Q_DECL_HIDDEN WaylandTasksModel::Private From 2fdeb890d741aadffda2601a04346fb7f2fdd4ae Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Thu, 22 Feb 2024 11:17:24 +0100 Subject: [PATCH 72/92] LXQtTaskbarWaylandBackend: do not show transient windows --- panel/backends/wayland/lxqttaskbarbackendwayland.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/panel/backends/wayland/lxqttaskbarbackendwayland.cpp b/panel/backends/wayland/lxqttaskbarbackendwayland.cpp index d85ec99d8..5def725ef 100644 --- a/panel/backends/wayland/lxqttaskbarbackendwayland.cpp +++ b/panel/backends/wayland/lxqttaskbarbackendwayland.cpp @@ -614,6 +614,9 @@ bool LXQtTaskbarWaylandBackend::acceptWindow(LXQtTaskBarPlasmaWindow *window) co if(window->windowState.testFlag(LXQtTaskBarPlasmaWindow::state::state_skiptaskbar)) return false; + if(transients.contains(window)) + return false; + return true; } From cc1befcc453245182ce1fe377e73667fc1fab2df Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Tue, 20 Feb 2024 10:04:23 +0100 Subject: [PATCH 73/92] LXQtTaskBarPlasmaWindowManagment: fix destructor TODO TODO: is this correct? Seems to call wl_proxy_destroy underneath --- panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp | 4 ++-- panel/backends/wayland/lxqttaskbarplasmawindowmanagment.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp b/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp index 3b765d3b3..f813181ed 100644 --- a/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp +++ b/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp @@ -1123,7 +1123,7 @@ LXQtTaskBarPlasmaWindowManagment::LXQtTaskBarPlasmaWindowManagment() { connect(this, &QWaylandClientExtension::activeChanged, this, [this] { if (!isActive()) { - wl_proxy_destroy(reinterpret_cast(object())); + org_kde_plasma_window_management_destroy(object()); } }); } @@ -1131,7 +1131,7 @@ LXQtTaskBarPlasmaWindowManagment::LXQtTaskBarPlasmaWindowManagment() LXQtTaskBarPlasmaWindowManagment::~LXQtTaskBarPlasmaWindowManagment() { if (isActive()) { - wl_proxy_destroy(reinterpret_cast(object())); + org_kde_plasma_window_management_destroy(object()); } } diff --git a/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.h b/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.h index c21b57b3c..976ac53e2 100644 --- a/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.h +++ b/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.h @@ -102,6 +102,7 @@ class LXQtTaskBarPlasmaWindowManagment : public QWaylandClientExtensionTemplate< Q_OBJECT public: static constexpr int version = 16; + LXQtTaskBarPlasmaWindowManagment(); ~LXQtTaskBarPlasmaWindowManagment(); From 6b206fd9e020c63f942f06921cd4045ab7b810e7 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Wed, 21 Feb 2024 11:52:48 +0100 Subject: [PATCH 74/92] LXQtPanel: basic virtual desktop support on Plasma Wayland --- panel/CMakeLists.txt | 7 + .../wayland/lxqtplasmavirtualdesktop.cpp | 231 ++++++++++++++++++ .../wayland/lxqtplasmavirtualdesktop.h | 87 +++++++ .../wayland/lxqttaskbarbackendwayland.cpp | 18 +- .../wayland/lxqttaskbarbackendwayland.h | 3 + .../org-kde-plasma-virtual-desktop.xml | 110 +++++++++ 6 files changed, 454 insertions(+), 2 deletions(-) create mode 100644 panel/backends/wayland/lxqtplasmavirtualdesktop.cpp create mode 100644 panel/backends/wayland/lxqtplasmavirtualdesktop.h create mode 100644 panel/backends/wayland/protocols/org-kde-plasma-virtual-desktop.xml diff --git a/panel/CMakeLists.txt b/panel/CMakeLists.txt index 6fb7c7608..8c02881fd 100644 --- a/panel/CMakeLists.txt +++ b/panel/CMakeLists.txt @@ -35,6 +35,7 @@ set(PRIV_HEADERS backends/wayland/lxqttaskbarbackendwayland.h backends/wayland/lxqttaskbarplasmawindowmanagment.h + backends/wayland/lxqtplasmavirtualdesktop.h ) # using LXQt namespace in the public headers. @@ -74,6 +75,7 @@ set(SOURCES backends/wayland/lxqttaskbarbackendwayland.cpp backends/wayland/lxqttaskbarplasmawindowmanagment.cpp + backends/wayland/lxqtplasmavirtualdesktop.cpp ) set(UI @@ -134,6 +136,11 @@ FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/wayland/protocols/plasma-window-management.xml ) +qt6_generate_wayland_protocol_client_sources(${PROJECT} +FILES + ${CMAKE_CURRENT_SOURCE_DIR}/backends/wayland/protocols/org-kde-plasma-virtual-desktop.xml +) + target_link_libraries(${PROJECT} ${LIBRARIES} ${QTX_LIBRARIES} diff --git a/panel/backends/wayland/lxqtplasmavirtualdesktop.cpp b/panel/backends/wayland/lxqtplasmavirtualdesktop.cpp new file mode 100644 index 000000000..a3d987f06 --- /dev/null +++ b/panel/backends/wayland/lxqtplasmavirtualdesktop.cpp @@ -0,0 +1,231 @@ +#include "lxqtplasmavirtualdesktop.h" + +#include + +LXQtPlasmaVirtualDesktop::LXQtPlasmaVirtualDesktop(::org_kde_plasma_virtual_desktop *object, const QString &id) + : org_kde_plasma_virtual_desktop(object) + , id(id) +{ +} + +LXQtPlasmaVirtualDesktop::~LXQtPlasmaVirtualDesktop() +{ + wl_proxy_destroy(reinterpret_cast(object())); +} + +void LXQtPlasmaVirtualDesktop::org_kde_plasma_virtual_desktop_name(const QString &name) +{ + this->name = name; +} + +void LXQtPlasmaVirtualDesktop::org_kde_plasma_virtual_desktop_done() +{ + Q_EMIT done(); +} + +void LXQtPlasmaVirtualDesktop::org_kde_plasma_virtual_desktop_activated() +{ + Q_EMIT activated(); +} + +LXQtPlasmaVirtualDesktopManagment::LXQtPlasmaVirtualDesktopManagment() + : QWaylandClientExtensionTemplate(version) +{ + connect(this, &QWaylandClientExtension::activeChanged, this, [this] { + if (!isActive()) { + org_kde_plasma_virtual_desktop_management_destroy(object()); + } + }); +} + +LXQtPlasmaVirtualDesktopManagment::~LXQtPlasmaVirtualDesktopManagment() +{ + if (isActive()) { + org_kde_plasma_virtual_desktop_management_destroy(object()); + } +} + +void LXQtPlasmaVirtualDesktopManagment::org_kde_plasma_virtual_desktop_management_desktop_created(const QString &desktop_id, uint32_t position) +{ + emit desktopCreated(desktop_id, position); +} + +void LXQtPlasmaVirtualDesktopManagment::org_kde_plasma_virtual_desktop_management_desktop_removed(const QString &desktop_id) +{ + emit desktopRemoved(desktop_id); +} + +void LXQtPlasmaVirtualDesktopManagment::org_kde_plasma_virtual_desktop_management_rows(uint32_t rows) +{ + emit rowsChanged(rows); +} + +LXQtPlasmaWaylandWorkspaceInfo::LXQtPlasmaWaylandWorkspaceInfo() +{ + init(); +} + +LXQtPlasmaWaylandWorkspaceInfo::VirtualDesktopsIterator LXQtPlasmaWaylandWorkspaceInfo::findDesktop(const QString &id) const +{ + return std::find_if(virtualDesktops.begin(), virtualDesktops.end(), + [&id](const std::unique_ptr &desktop) { + return desktop->id == id; + }); +} + +void LXQtPlasmaWaylandWorkspaceInfo::init() +{ + virtualDesktopManagement = std::make_unique(); + + connect(virtualDesktopManagement.get(), &LXQtPlasmaVirtualDesktopManagment::activeChanged, this, [this] { + if (!virtualDesktopManagement->isActive()) { + rows = 0; + virtualDesktops.clear(); + currentVirtualDesktop.clear(); + Q_EMIT currentDesktopChanged(); + Q_EMIT numberOfDesktopsChanged(); + Q_EMIT navigationWrappingAroundChanged(); + Q_EMIT desktopIdsChanged(); + Q_EMIT desktopNamesChanged(); + Q_EMIT desktopLayoutRowsChanged(); + } + }); + + connect(virtualDesktopManagement.get(), &LXQtPlasmaVirtualDesktopManagment::desktopCreated, + this, &LXQtPlasmaWaylandWorkspaceInfo::addDesktop); + + connect(virtualDesktopManagement.get(), &LXQtPlasmaVirtualDesktopManagment::desktopRemoved, this, [this](const QString &id) { + + + std::remove_if(virtualDesktops.begin(), virtualDesktops.end(), + [id](const std::unique_ptr &desktop) + { + return desktop->id == id; + }); + + Q_EMIT numberOfDesktopsChanged(); + Q_EMIT desktopIdsChanged(); + Q_EMIT desktopNamesChanged(); + + if (currentVirtualDesktop == id) { + currentVirtualDesktop.clear(); + Q_EMIT currentDesktopChanged(); + } + }); + + connect(virtualDesktopManagement.get(), &LXQtPlasmaVirtualDesktopManagment::rowsChanged, this, [this](quint32 rows) { + this->rows = rows; + Q_EMIT desktopLayoutRowsChanged(); + }); +} + +void LXQtPlasmaWaylandWorkspaceInfo::addDesktop(const QString &id, quint32 position) +{ + if (findDesktop(id) != virtualDesktops.end()) { + return; + } + + auto desktop = std::make_unique(virtualDesktopManagement->get_virtual_desktop(id), id); + + connect(desktop.get(), &LXQtPlasmaVirtualDesktop::activated, this, [id, this]() { + currentVirtualDesktop = id; + Q_EMIT currentDesktopChanged(); + }); + + connect(desktop.get(), &LXQtPlasmaVirtualDesktop::done, this, [this]() { + Q_EMIT desktopNamesChanged(); + }); + + virtualDesktops.insert(std::next(virtualDesktops.begin(), position), std::move(desktop)); + + Q_EMIT numberOfDesktopsChanged(); + Q_EMIT desktopIdsChanged(); + Q_EMIT desktopNamesChanged(); +} + +QVariant LXQtPlasmaWaylandWorkspaceInfo::currentDesktop() const +{ + return currentVirtualDesktop; +} + +int LXQtPlasmaWaylandWorkspaceInfo::numberOfDesktops() const +{ + return virtualDesktops.size(); +} + +quint32 LXQtPlasmaWaylandWorkspaceInfo::position(const QVariant &desktop) const +{ + return std::distance(virtualDesktops.begin(), findDesktop(desktop.toString())); +} + +QVariantList LXQtPlasmaWaylandWorkspaceInfo::desktopIds() const +{ + QVariantList ids; + ids.reserve(virtualDesktops.size()); + + std::transform(virtualDesktops.cbegin(), virtualDesktops.cend(), std::back_inserter(ids), [](const std::unique_ptr &desktop) { + return desktop->id; + }); + return ids; +} + +QStringList LXQtPlasmaWaylandWorkspaceInfo::desktopNames() const +{ + if (!virtualDesktopManagement->isActive()) { + return QStringList(); + } + QStringList names; + names.reserve(virtualDesktops.size()); + + std::transform(virtualDesktops.cbegin(), virtualDesktops.cend(), std::back_inserter(names), [](const std::unique_ptr &desktop) { + return desktop->name; + }); + return names; +} + +int LXQtPlasmaWaylandWorkspaceInfo::desktopLayoutRows() const +{ + if (!virtualDesktopManagement->isActive()) { + return 0; + } + + return rows; +} + +void LXQtPlasmaWaylandWorkspaceInfo::requestActivate(const QVariant &desktop) +{ + if (!virtualDesktopManagement->isActive()) { + return; + } + + if (auto it = findDesktop(desktop.toString()); it != virtualDesktops.end()) { + (*it)->request_activate(); + } +} + +void LXQtPlasmaWaylandWorkspaceInfo::requestCreateDesktop(quint32 position) +{ + if (!virtualDesktopManagement->isActive()) { + return; + } + + //TODO: translatestd + virtualDesktopManagement->request_create_virtual_desktop(QLatin1String("New Desktop"), position); +} + +void LXQtPlasmaWaylandWorkspaceInfo::requestRemoveDesktop(quint32 position) +{ + if (!virtualDesktopManagement->isActive()) { + return; + } + if (virtualDesktops.size() == 1) { + return; + } + + if (position > (virtualDesktops.size() - 1)) { + return; + } + + virtualDesktopManagement->request_remove_virtual_desktop(virtualDesktops.at(position)->id); +} + diff --git a/panel/backends/wayland/lxqtplasmavirtualdesktop.h b/panel/backends/wayland/lxqtplasmavirtualdesktop.h new file mode 100644 index 000000000..3dabb6242 --- /dev/null +++ b/panel/backends/wayland/lxqtplasmavirtualdesktop.h @@ -0,0 +1,87 @@ +#ifndef LXQTPLASMAVIRTUALDESKTOP_H +#define LXQTPLASMAVIRTUALDESKTOP_H + +#include +#include + +#include + +#include "qwayland-org-kde-plasma-virtual-desktop.h" + +class LXQtPlasmaVirtualDesktop : public QObject, public QtWayland::org_kde_plasma_virtual_desktop +{ + Q_OBJECT +public: + LXQtPlasmaVirtualDesktop(::org_kde_plasma_virtual_desktop *object, const QString &id); + ~LXQtPlasmaVirtualDesktop(); + const QString id; + QString name; +Q_SIGNALS: + void done(); + void activated(); + +protected: + void org_kde_plasma_virtual_desktop_name(const QString &name) override; + void org_kde_plasma_virtual_desktop_done() override; + void org_kde_plasma_virtual_desktop_activated() override; +}; + + +class LXQtPlasmaVirtualDesktopManagment : public QWaylandClientExtensionTemplate, + public QtWayland::org_kde_plasma_virtual_desktop_management +{ + Q_OBJECT +public: + static constexpr int version = 2; + + LXQtPlasmaVirtualDesktopManagment(); + ~LXQtPlasmaVirtualDesktopManagment(); + +signals: + void desktopCreated(const QString &id, quint32 position); + void desktopRemoved(const QString &id); + void rowsChanged(const quint32 rows); + +protected: + virtual void org_kde_plasma_virtual_desktop_management_desktop_created(const QString &desktop_id, uint32_t position) override; + virtual void org_kde_plasma_virtual_desktop_management_desktop_removed(const QString &desktop_id) override; + virtual void org_kde_plasma_virtual_desktop_management_rows(uint32_t rows) override; +}; + +class Q_DECL_HIDDEN LXQtPlasmaWaylandWorkspaceInfo : public QObject +{ + Q_OBJECT +public: + LXQtPlasmaWaylandWorkspaceInfo(); + + QVariant currentVirtualDesktop; + std::vector> virtualDesktops; + std::unique_ptr virtualDesktopManagement; + quint32 rows; + + typedef std::vector>::const_iterator VirtualDesktopsIterator; + + VirtualDesktopsIterator findDesktop(const QString &id) const; + + void init(); + void addDesktop(const QString &id, quint32 position); + QVariant currentDesktop() const; + int numberOfDesktops() const; + QVariantList desktopIds() const; + QStringList desktopNames() const; + quint32 position(const QVariant &desktop) const; + int desktopLayoutRows() const; + void requestActivate(const QVariant &desktop); + void requestCreateDesktop(quint32 position); + void requestRemoveDesktop(quint32 position); + +signals: + void currentDesktopChanged(); + void numberOfDesktopsChanged(); + void navigationWrappingAroundChanged(); + void desktopIdsChanged(); + void desktopNamesChanged(); + void desktopLayoutRowsChanged(); +}; + +#endif // LXQTPLASMAVIRTUALDESKTOP_H diff --git a/panel/backends/wayland/lxqttaskbarbackendwayland.cpp b/panel/backends/wayland/lxqttaskbarbackendwayland.cpp index 5def725ef..57b77c906 100644 --- a/panel/backends/wayland/lxqttaskbarbackendwayland.cpp +++ b/panel/backends/wayland/lxqttaskbarbackendwayland.cpp @@ -1,6 +1,7 @@ #include "lxqttaskbarbackendwayland.h" #include "lxqttaskbarplasmawindowmanagment.h" +#include "lxqtplasmavirtualdesktop.h" #include #include @@ -25,6 +26,7 @@ LXQtTaskbarWaylandBackend::LXQtTaskbarWaylandBackend(QObject *parent) : ILXQtTaskbarAbstractBackend(parent) { m_managment.reset(new LXQtTaskBarPlasmaWindowManagment); + m_workspaceInfo.reset(new LXQtPlasmaWaylandWorkspaceInfo); connect(m_managment.get(), &LXQtTaskBarPlasmaWindowManagment::windowCreated, this, [this](LXQtTaskBarPlasmaWindow *window) { connect(window, &LXQtTaskBarPlasmaWindow::initialStateDone, this, [this, window] { @@ -39,6 +41,17 @@ LXQtTaskbarWaylandBackend::LXQtTaskbarWaylandBackend(QObject *parent) : // // this->dataChanged(window.get(), StackingOrder); // // } // }); + + connect(m_workspaceInfo.get(), &LXQtPlasmaWaylandWorkspaceInfo::currentDesktopChanged, this, + [this](){ + int idx = m_workspaceInfo->position(m_workspaceInfo->currentDesktop()); + emit currentWorkspaceChanged(idx); + }); + + connect(m_workspaceInfo.get(), &LXQtPlasmaWaylandWorkspaceInfo::numberOfDesktopsChanged, + this, &ILXQtTaskbarAbstractBackend::workspacesCountChanged); + + //TODO: connect name changed } bool LXQtTaskbarWaylandBackend::supportsAction(WId windowId, LXQtTaskBarBackendAction action) const @@ -291,12 +304,13 @@ WId LXQtTaskbarWaylandBackend::getActiveWindow() const int LXQtTaskbarWaylandBackend::getWorkspacesCount() const { - return 1; //TODO + return m_workspaceInfo->numberOfDesktops(); } QString LXQtTaskbarWaylandBackend::getWorkspaceName(int idx) const { - return QStringLiteral("TestWorkspace"); + //TODO: optimize + return m_workspaceInfo->desktopNames().value(idx, QStringLiteral("ERROR")); } int LXQtTaskbarWaylandBackend::getCurrentWorkspace() const diff --git a/panel/backends/wayland/lxqttaskbarbackendwayland.h b/panel/backends/wayland/lxqttaskbarbackendwayland.h index 77d857eb9..0b12ef2fd 100644 --- a/panel/backends/wayland/lxqttaskbarbackendwayland.h +++ b/panel/backends/wayland/lxqttaskbarbackendwayland.h @@ -8,6 +8,7 @@ class LXQtTaskBarPlasmaWindow; class LXQtTaskBarPlasmaWindowManagment; +class LXQtPlasmaWaylandWorkspaceInfo; class LXQtTaskbarWaylandBackend : public ILXQtTaskbarAbstractBackend @@ -77,6 +78,8 @@ class LXQtTaskbarWaylandBackend : public ILXQtTaskbarAbstractBackend private: LXQtTaskBarPlasmaWindow *getWindow(WId windowId) const; + std::unique_ptr m_workspaceInfo; + std::unique_ptr m_managment; QHash lastActivated; diff --git a/panel/backends/wayland/protocols/org-kde-plasma-virtual-desktop.xml b/panel/backends/wayland/protocols/org-kde-plasma-virtual-desktop.xml new file mode 100644 index 000000000..0e0551b0a --- /dev/null +++ b/panel/backends/wayland/protocols/org-kde-plasma-virtual-desktop.xml @@ -0,0 +1,110 @@ + + + + + + + + Given the id of a particular virtual desktop, get the corresponding org_kde_plasma_virtual_desktop which represents only the desktop with that id. + + + + + + + + Ask the server to create a new virtual desktop, and position it at a specified position. If the position is zero or less, it will be positioned at the beginning, if the position is the count or more, it will be positioned at the end. + + + + + + + + Ask the server to get rid of a virtual desktop, the server may or may not acconsent to the request. + + + + + + + + + + + + + + + + + + + This event is sent after all other properties has been + sent after binding to the desktop manager object and after any + other property changes done after that. This allows + changes to the org_kde_plasma_virtual_desktop_management properties to be seen as + atomic, even if they happen via multiple events. + + + + + + + + + + + + + Request the server to set the status of this desktop to active: The server is free to consent or deny the request. This will be the new "current" virtual desktop of the system. + + + + + + The format of the id is decided by the compositor implementation. A desktop id univocally identifies a virtual desktop and must be guaranteed to never exist two desktops with the same id. The format of the string id is up to the server implementation. + + + + + + + + + + + The desktop will be the new "current" desktop of the system. The server may support either one virtual desktop active at a time, or other combinations such as one virtual desktop active per screen. + Windows associated to this virtual desktop will be shown. + + + + + + Windows that were associated only to this desktop will be hidden. + + + + + + This event is sent after all other properties has been + sent after binding to the desktop object and after any + other property changes done after that. This allows + changes to the org_kde_plasma_virtual_desktop properties to be seen as + atomic, even if they happen via multiple events. + + + + + + This virtual desktop has just been removed by the server: + All windows will lose the association to this desktop. + + + + + From df9ec875cc4d9e720c3af23fc444fdcaa11cffc2 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 17 Feb 2024 23:32:46 +0100 Subject: [PATCH 75/92] LXQtPanel: workaround KAcceleratorManager changing button text FIXME TODO TODO: is this correct approach? --- plugin-taskbar/lxqttaskbutton.cpp | 27 ++++++++++++++++++++++++++- plugin-taskbar/lxqttaskbutton.h | 4 ++++ plugin-taskbar/lxqttaskgroup.cpp | 6 +++--- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/plugin-taskbar/lxqttaskbutton.cpp b/plugin-taskbar/lxqttaskbutton.cpp index c2e2a0282..c9e0c57df 100644 --- a/plugin-taskbar/lxqttaskbutton.cpp +++ b/plugin-taskbar/lxqttaskbutton.cpp @@ -128,7 +128,7 @@ LXQtTaskButton::~LXQtTaskButton() = default; void LXQtTaskButton::updateText() { QString title = mBackend->getWindowTitle(mWindow); - setText(title.replace(QStringLiteral("&"), QStringLiteral("&&"))); + setTextExplicitly(title.replace(QStringLiteral("&"), QStringLiteral("&&"))); setToolTip(title); } @@ -314,6 +314,30 @@ QMimeData * LXQtTaskButton::mimeData() return mimedata; } +/*! + * \brief LXQtTaskButton::setTextExplicitly + * \param str + * + * This is needed to workaround flickering caused by KAcceleratorManager + * This class is hooked by KDE Integration and adds accelerators to button text + * (Adds some '&' characters) + * This triggers widget update but soon after text is reset to original value + * This triggers a KAcceleratorManager update which again adds accelerator + * This happens in loop + * + * TODO: investigate proper solution + */ +void LXQtTaskButton::setTextExplicitly(const QString &str) +{ + if(str == mExplicitlySetText) + { + return; + } + + mExplicitlySetText = str; + setText(mExplicitlySetText); +} + /************************************************ ************************************************/ @@ -687,6 +711,7 @@ void LXQtTaskButton::contextMenuEvent(QContextMenuEvent* event) menu->addSeparator(); a = menu->addAction(XdgIcon::fromTheme(QStringLiteral("process-stop")), tr("&Close")); connect(a, &QAction::triggered, this, &LXQtTaskButton::closeApplication); + menu->setGeometry(mParentTaskBar->panel()->calculatePopupWindowPos(mapToGlobal(event->pos()), menu->sizeHint())); mPlugin->willShowWindow(menu); menu->show(); diff --git a/plugin-taskbar/lxqttaskbutton.h b/plugin-taskbar/lxqttaskbutton.h index 9ccca36fa..6d5841df4 100644 --- a/plugin-taskbar/lxqttaskbutton.h +++ b/plugin-taskbar/lxqttaskbutton.h @@ -122,6 +122,8 @@ public slots: inline ILXQtPanelPlugin * plugin() const { return mPlugin; } + void setTextExplicitly(const QString& str); + protected: //TODO: public getter instead? ILXQtTaskbarAbstractBackend *mBackend; @@ -138,6 +140,8 @@ public slots: int mIconSize; int mWheelDelta; + QString mExplicitlySetText; + // Timer for when draggind something into a button (the button's window // must be activated so that the use can continue dragging to the window QTimer * mDNDTimer; diff --git a/plugin-taskbar/lxqttaskgroup.cpp b/plugin-taskbar/lxqttaskgroup.cpp index c6075df89..f7da5ef21 100644 --- a/plugin-taskbar/lxqttaskgroup.cpp +++ b/plugin-taskbar/lxqttaskgroup.cpp @@ -57,7 +57,7 @@ LXQtTaskGroup::LXQtTaskGroup(const QString &groupName, WId window, LXQtTaskBar * Q_ASSERT(parent); setObjectName(groupName); - setText(groupName); + setTextExplicitly(groupName); connect(this, &LXQtTaskGroup::clicked, this, &LXQtTaskGroup::onClicked); connect(parent, &LXQtTaskBar::buttonRotationRefreshed, this, &LXQtTaskGroup::setAutoRotation); @@ -336,7 +336,7 @@ void LXQtTaskGroup::regroup() if (button) { - setText(button->text()); + setTextExplicitly(button->text()); setToolTip(button->toolTip()); setWindowId(button->windowId()); } @@ -347,7 +347,7 @@ void LXQtTaskGroup::regroup() { mSingleButton = false; QString t = QString(QStringLiteral("%1 - %2 windows")).arg(mGroupName).arg(cont); - setText(t); + setTextExplicitly(t); setToolTip(parentTaskBar()->isShowGroupOnHover() ? QString() : t); } } From 8d1b9560d75a8c1422d2062fdc18fc639e432671 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 17 Feb 2024 23:16:24 +0100 Subject: [PATCH 76/92] LXQtPanel: use LayerShell on Wayland layer_shell protocol allows to aks for placement on Wayland --- CMakeLists.txt | 2 + panel/CMakeLists.txt | 1 + panel/lxqtpanel.cpp | 172 +++++++++++++++++++++++++++++++------------ panel/lxqtpanel.h | 6 ++ 4 files changed, 134 insertions(+), 47 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 25350186d..3cd60ede7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,8 @@ 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) +find_package(LayerShellQt REQUIRED) + # Patch Version set(LXQT_PANEL_PATCH_VERSION 0) set(LXQT_PANEL_VERSION ${LXQT_MAJOR_VERSION}.${LXQT_MINOR_VERSION}.${LXQT_PANEL_PATCH_VERSION}) diff --git a/panel/CMakeLists.txt b/panel/CMakeLists.txt index 8c02881fd..d1008d561 100644 --- a/panel/CMakeLists.txt +++ b/panel/CMakeLists.txt @@ -147,6 +147,7 @@ target_link_libraries(${PROJECT} KF6::WindowSystem Qt6::WaylandClient # TODO: Move to backend folder Qt6::Concurrent + LayerShellQt::Interface ${STATIC_PLUGINS} ) diff --git a/panel/lxqtpanel.cpp b/panel/lxqtpanel.cpp index b704fdd3d..ebadfe0d3 100644 --- a/panel/lxqtpanel.cpp +++ b/panel/lxqtpanel.cpp @@ -54,6 +54,7 @@ #include "backends/ilxqttaskbarabstractbackend.h" +#include // Turn on this to show the time required to load each plugin during startup // #define DEBUG_PLUGIN_LOADTIME @@ -143,6 +144,7 @@ LXQtPanel::LXQtPanel(const QString &configGroup, LXQt::Settings *settings, QWidg mAnimationTime(0), mReserveSpace(true), mAnimation(nullptr), + mLayerWindow(nullptr), mLockPanel(false) { //You can find information about the flags and widget attributes in your @@ -232,6 +234,30 @@ LXQtPanel::LXQtPanel(const QString &configGroup, LXQt::Settings *settings, QWidg loadPlugins(); + if(qGuiApp->nativeInterface()) + { + // Create backing QWindow for LayerShellQt integration + create(); + + // Init Layer Shell (Must be done before showing widget) + mLayerWindow = LayerShellQt::Window::get(windowHandle()); + mLayerWindow->setLayer(LayerShellQt::Window::LayerTop); + + mLayerWindow->setScope(QStringLiteral("dock")); + + LayerShellQt::Window::Anchors anchors; + anchors.setFlag(LayerShellQt::Window::AnchorLeft); + anchors.setFlag(LayerShellQt::Window::AnchorBottom); + anchors.setFlag(LayerShellQt::Window::AnchorRight); + mLayerWindow->setAnchors(anchors); + + mLayerWindow->setKeyboardInteractivity(LayerShellQt::Window::KeyboardInteractivityNone); + mLayerWindow->setCloseOnDismissed(false); + + mLayerWindow->setExclusiveEdge(LayerShellQt::Window::AnchorBottom); + mLayerWindow->setExclusiveZone(height()); + } + // NOTE: Some (X11) WMs may need the geometry to be set before QWidget::show(). setPanelGeometry(); @@ -485,6 +511,7 @@ void LXQtPanel::setPanelGeometry(bool animate) const QRect currentScreen = screens.at(mActualScreenNum)->geometry(); QRect rect; + LayerShellQt::Window::Anchors anchors; if (isHorizontal()) { @@ -521,6 +548,9 @@ void LXQtPanel::setPanelGeometry(bool animate) // Vert ....................... if (mPosition == ILXQtPanel::PositionTop) { + anchors.setFlag(LayerShellQt::Window::AnchorTop); + anchors.setFlag(LayerShellQt::Window::AnchorLeft); + anchors.setFlag(LayerShellQt::Window::AnchorRight); if (mHidden) rect.moveBottom(currentScreen.top() + PANEL_HIDE_SIZE - 1); else @@ -528,6 +558,9 @@ void LXQtPanel::setPanelGeometry(bool animate) } else { + anchors.setFlag(LayerShellQt::Window::AnchorBottom); + anchors.setFlag(LayerShellQt::Window::AnchorLeft); + anchors.setFlag(LayerShellQt::Window::AnchorRight); if (mHidden) rect.moveTop(currentScreen.bottom() - PANEL_HIDE_SIZE + 1); else @@ -569,6 +602,9 @@ void LXQtPanel::setPanelGeometry(bool animate) // Horiz ...................... if (mPosition == ILXQtPanel::PositionLeft) { + anchors.setFlag(LayerShellQt::Window::AnchorTop); + anchors.setFlag(LayerShellQt::Window::AnchorLeft); + anchors.setFlag(LayerShellQt::Window::AnchorBottom); if (mHidden) rect.moveRight(currentScreen.left() + PANEL_HIDE_SIZE - 1); else @@ -576,12 +612,19 @@ void LXQtPanel::setPanelGeometry(bool animate) } else { + anchors.setFlag(LayerShellQt::Window::AnchorTop); + anchors.setFlag(LayerShellQt::Window::AnchorRight); + anchors.setFlag(LayerShellQt::Window::AnchorBottom); if (mHidden) rect.moveLeft(currentScreen.right() - PANEL_HIDE_SIZE + 1); else rect.moveRight(currentScreen.right()); } } + + if(mLayerWindow) + mLayerWindow->setAnchors(anchors); + if (!mHidden || !mGeometry.isValid()) mGeometry = rect; if (rect != geometry()) { @@ -670,62 +713,97 @@ void LXQtPanel::updateWmStrut() if(wid == 0 || !isVisible()) return; - if (mReserveSpace && QApplication::primaryScreen()) + if(qGuiApp->nativeInterface()) { - const QRect wholeScreen = QApplication::primaryScreen()->virtualGeometry(); - const QRect rect = geometry(); - // NOTE: https://standards.freedesktop.org/wm-spec/wm-spec-latest.html - // Quote from the EWMH spec: " Note that the strut is relative to the screen edge, and not the edge of the xinerama monitor." - // So, we use the geometry of the whole screen to calculate the strut rather than using the geometry of individual monitors. - // Though the spec only mention Xinerama and did not mention XRandR, the rule should still be applied. - // At least openbox is implemented like this. - switch (mPosition) + if (mReserveSpace && QApplication::primaryScreen()) { - case LXQtPanel::PositionTop: - KX11Extras::setExtendedStrut(wid, - /* Left */ 0, 0, 0, - /* Right */ 0, 0, 0, - /* Top */ rect.top() + getReserveDimension(), rect.left(), rect.right(), - /* Bottom */ 0, 0, 0 - ); - break; + const QRect wholeScreen = QApplication::primaryScreen()->virtualGeometry(); + const QRect rect = geometry(); + // NOTE: https://standards.freedesktop.org/wm-spec/wm-spec-latest.html + // Quote from the EWMH spec: " Note that the strut is relative to the screen edge, and not the edge of the xinerama monitor." + // So, we use the geometry of the whole screen to calculate the strut rather than using the geometry of individual monitors. + // Though the spec only mention Xinerama and did not mention XRandR, the rule should still be applied. + // At least openbox is implemented like this. + switch (mPosition) + { + case LXQtPanel::PositionTop: + KX11Extras::setExtendedStrut(wid, + /* Left */ 0, 0, 0, + /* Right */ 0, 0, 0, + /* Top */ rect.top() + getReserveDimension(), rect.left(), rect.right(), + /* Bottom */ 0, 0, 0 + ); + break; - case LXQtPanel::PositionBottom: - KX11Extras::setExtendedStrut(wid, - /* Left */ 0, 0, 0, - /* Right */ 0, 0, 0, - /* Top */ 0, 0, 0, - /* Bottom */ wholeScreen.bottom() - rect.bottom() + getReserveDimension(), rect.left(), rect.right() - ); - break; + case LXQtPanel::PositionBottom: + KX11Extras::setExtendedStrut(wid, + /* Left */ 0, 0, 0, + /* Right */ 0, 0, 0, + /* Top */ 0, 0, 0, + /* Bottom */ wholeScreen.bottom() - rect.bottom() + getReserveDimension(), rect.left(), rect.right() + ); + break; - case LXQtPanel::PositionLeft: - KX11Extras::setExtendedStrut(wid, - /* Left */ rect.left() + getReserveDimension(), rect.top(), rect.bottom(), - /* Right */ 0, 0, 0, - /* Top */ 0, 0, 0, - /* Bottom */ 0, 0, 0 - ); + case LXQtPanel::PositionLeft: + KX11Extras::setExtendedStrut(wid, + /* Left */ rect.left() + getReserveDimension(), rect.top(), rect.bottom(), + /* Right */ 0, 0, 0, + /* Top */ 0, 0, 0, + /* Bottom */ 0, 0, 0 + ); - break; + break; - case LXQtPanel::PositionRight: + case LXQtPanel::PositionRight: + KX11Extras::setExtendedStrut(wid, + /* Left */ 0, 0, 0, + /* Right */ wholeScreen.right() - rect.right() + getReserveDimension(), rect.top(), rect.bottom(), + /* Top */ 0, 0, 0, + /* Bottom */ 0, 0, 0 + ); + break; + } + } else + { KX11Extras::setExtendedStrut(wid, - /* Left */ 0, 0, 0, - /* Right */ wholeScreen.right() - rect.right() + getReserveDimension(), rect.top(), rect.bottom(), - /* Top */ 0, 0, 0, - /* Bottom */ 0, 0, 0 - ); - break; + /* Left */ 0, 0, 0, + /* Right */ 0, 0, 0, + /* Top */ 0, 0, 0, + /* Bottom */ 0, 0, 0 + ); + } } - } else + else if(qGuiApp->nativeInterface()) { - KX11Extras::setExtendedStrut(wid, - /* Left */ 0, 0, 0, - /* Right */ 0, 0, 0, - /* Top */ 0, 0, 0, - /* Bottom */ 0, 0, 0 - ); + if (mReserveSpace) + { + switch (mPosition) + { + case LXQtPanel::PositionTop: + mLayerWindow->setExclusiveEdge(LayerShellQt::Window::AnchorTop); + mLayerWindow->setExclusiveZone(height()); + break; + + case LXQtPanel::PositionBottom: + mLayerWindow->setExclusiveEdge(LayerShellQt::Window::AnchorBottom); + mLayerWindow->setExclusiveZone(height()); + break; + + case LXQtPanel::PositionLeft: + mLayerWindow->setExclusiveEdge(LayerShellQt::Window::AnchorLeft); + mLayerWindow->setExclusiveZone(width()); + break; + + case LXQtPanel::PositionRight: + mLayerWindow->setExclusiveEdge(LayerShellQt::Window::AnchorRight); + mLayerWindow->setExclusiveZone(width()); + break; + } + } else + { + mLayerWindow->setExclusiveEdge(LayerShellQt::Window::AnchorNone); + mLayerWindow->setExclusiveZone(0); + } } } diff --git a/panel/lxqtpanel.h b/panel/lxqtpanel.h index a3a061a53..ed952dbdb 100644 --- a/panel/lxqtpanel.h +++ b/panel/lxqtpanel.h @@ -42,6 +42,10 @@ class QMenu; class Plugin; class QAbstractItemModel; +namespace LayerShellQt { +class Window; +} + namespace LXQt { class Settings; class PluginInfo; @@ -689,6 +693,8 @@ private slots: */ QPropertyAnimation *mAnimation; + LayerShellQt::Window *mLayerWindow; + /** * @brief Flag for providing the configuration options in panel's context menu */ From 318ad8159cf92b2669a04731cc2f63b2e9ad795f Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Thu, 22 Feb 2024 11:44:11 +0100 Subject: [PATCH 77/92] LXQtPanel: fix position not applied immediatly on Wayland --- panel/lxqtpanel.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/panel/lxqtpanel.cpp b/panel/lxqtpanel.cpp index ebadfe0d3..529b74a61 100644 --- a/panel/lxqtpanel.cpp +++ b/panel/lxqtpanel.cpp @@ -652,6 +652,10 @@ void LXQtPanel::setPanelGeometry(bool animate) setGeometry(rect); } } + + // Make LayerShell apply changes immediatly + if(windowHandle()) + windowHandle()->requestUpdate(); } void LXQtPanel::setMargins() From 355b0db6de291d27a4a0acfe71285b52fcf91b8e Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Thu, 22 Feb 2024 12:10:02 +0100 Subject: [PATCH 78/92] LXQtPanel: partially fix alignment on Wayland TODO TODO: after changing length to pixels and back to percent alignment is ignored and always kept to right --- panel/lxqtpanel.cpp | 49 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/panel/lxqtpanel.cpp b/panel/lxqtpanel.cpp index 529b74a61..336f1f4cd 100644 --- a/panel/lxqtpanel.cpp +++ b/panel/lxqtpanel.cpp @@ -512,6 +512,7 @@ void LXQtPanel::setPanelGeometry(bool animate) QRect rect; LayerShellQt::Window::Anchors anchors; + LayerShellQt::Window::Anchor edge; if (isHorizontal()) { @@ -533,6 +534,7 @@ void LXQtPanel::setPanelGeometry(bool animate) switch (mAlignment) { case LXQtPanel::AlignmentLeft: + anchors.setFlag(LayerShellQt::Window::AnchorLeft); rect.moveLeft(currentScreen.left()); break; @@ -541,16 +543,24 @@ void LXQtPanel::setPanelGeometry(bool animate) break; case LXQtPanel::AlignmentRight: + anchors.setFlag(LayerShellQt::Window::AnchorRight); rect.moveRight(currentScreen.right()); break; } + if(lengthInPercents() && mLength == 100) + { + //Fill all available width + anchors.setFlag(LayerShellQt::Window::AnchorLeft); + anchors.setFlag(LayerShellQt::Window::AnchorRight); + } + // Vert ....................... if (mPosition == ILXQtPanel::PositionTop) { anchors.setFlag(LayerShellQt::Window::AnchorTop); - anchors.setFlag(LayerShellQt::Window::AnchorLeft); - anchors.setFlag(LayerShellQt::Window::AnchorRight); + edge = LayerShellQt::Window::AnchorTop; + if (mHidden) rect.moveBottom(currentScreen.top() + PANEL_HIDE_SIZE - 1); else @@ -559,8 +569,8 @@ void LXQtPanel::setPanelGeometry(bool animate) else { anchors.setFlag(LayerShellQt::Window::AnchorBottom); - anchors.setFlag(LayerShellQt::Window::AnchorLeft); - anchors.setFlag(LayerShellQt::Window::AnchorRight); + edge = LayerShellQt::Window::AnchorBottom; + if (mHidden) rect.moveTop(currentScreen.bottom() - PANEL_HIDE_SIZE + 1); else @@ -587,6 +597,7 @@ void LXQtPanel::setPanelGeometry(bool animate) switch (mAlignment) { case LXQtPanel::AlignmentLeft: + anchors.setFlag(LayerShellQt::Window::AnchorTop); rect.moveTop(currentScreen.top()); break; @@ -595,16 +606,24 @@ void LXQtPanel::setPanelGeometry(bool animate) break; case LXQtPanel::AlignmentRight: + anchors.setFlag(LayerShellQt::Window::AnchorBottom); rect.moveBottom(currentScreen.bottom()); break; } + if(lengthInPercents() && mLength == 100) + { + //Fill all available width + anchors.setFlag(LayerShellQt::Window::AnchorTop); + anchors.setFlag(LayerShellQt::Window::AnchorBottom); + } + // Horiz ...................... if (mPosition == ILXQtPanel::PositionLeft) { - anchors.setFlag(LayerShellQt::Window::AnchorTop); anchors.setFlag(LayerShellQt::Window::AnchorLeft); - anchors.setFlag(LayerShellQt::Window::AnchorBottom); + edge = LayerShellQt::Window::AnchorLeft; + if (mHidden) rect.moveRight(currentScreen.left() + PANEL_HIDE_SIZE - 1); else @@ -612,9 +631,9 @@ void LXQtPanel::setPanelGeometry(bool animate) } else { - anchors.setFlag(LayerShellQt::Window::AnchorTop); anchors.setFlag(LayerShellQt::Window::AnchorRight); - anchors.setFlag(LayerShellQt::Window::AnchorBottom); + edge = LayerShellQt::Window::AnchorRight; + if (mHidden) rect.moveLeft(currentScreen.right() - PANEL_HIDE_SIZE + 1); else @@ -623,7 +642,13 @@ void LXQtPanel::setPanelGeometry(bool animate) } if(mLayerWindow) + { mLayerWindow->setAnchors(anchors); + mLayerWindow->setExclusiveEdge(edge); + + // Make LayerShell apply changes immediatly + windowHandle()->requestUpdate(); + } if (!mHidden || !mGeometry.isValid()) mGeometry = rect; if (rect != geometry()) @@ -652,10 +677,6 @@ void LXQtPanel::setPanelGeometry(bool animate) setGeometry(rect); } } - - // Make LayerShell apply changes immediatly - if(windowHandle()) - windowHandle()->requestUpdate(); } void LXQtPanel::setMargins() @@ -779,6 +800,8 @@ void LXQtPanel::updateWmStrut() } else if(qGuiApp->nativeInterface()) { + //TODO: duplicated code, also set in setPanelGeometry() + if (mReserveSpace) { switch (mPosition) @@ -808,6 +831,8 @@ void LXQtPanel::updateWmStrut() mLayerWindow->setExclusiveEdge(LayerShellQt::Window::AnchorNone); mLayerWindow->setExclusiveZone(0); } + + windowHandle()->requestUpdate(); } } From 3f9bcb2450e573ca4ea87d1cdb10e807931e9089 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Thu, 22 Feb 2024 14:19:31 +0100 Subject: [PATCH 79/92] Add desktop file to be recognized by KWin Wayland NOTE: absolute path is needed inside .desktop file for this to work --- autostart/CMakeLists.txt | 7 +++++++ autostart/lxqt-panel_wayland.desktop | 13 +++++++++++++ panel/lxqtpanelapplication.cpp | 2 ++ 3 files changed, 22 insertions(+) create mode 100644 autostart/lxqt-panel_wayland.desktop diff --git a/autostart/CMakeLists.txt b/autostart/CMakeLists.txt index 098103168..2c9279a93 100644 --- a/autostart/CMakeLists.txt +++ b/autostart/CMakeLists.txt @@ -14,3 +14,10 @@ install(FILES DESTINATION "${LXQT_ETC_XDG_DIR}/autostart" COMPONENT Runtime ) + +install(FILES + lxqt-panel_wayland.desktop + DESTINATION "/usr/share/applications" + RENAME "lxqt-panel.desktop" + COMPONENT Runtime +) diff --git a/autostart/lxqt-panel_wayland.desktop b/autostart/lxqt-panel_wayland.desktop new file mode 100644 index 000000000..5b03e4120 --- /dev/null +++ b/autostart/lxqt-panel_wayland.desktop @@ -0,0 +1,13 @@ +[Desktop Entry] +Type=Application +TryExec=lxqt-panel + +# NOTE: KWin wants absolute path here, make sure it's correct +Exec=/usr/local/bin/lxqt-panel + +# NOTE: adding KDE to make it work under Plasma Wayland session +OnlyShowIn=LXQt;KDE +X-LXQt-Module=true + +# Make KWin recognize us as priviledged client +X-KDE-Wayland-Interfaces=org_kde_plasma_window_management diff --git a/panel/lxqtpanelapplication.cpp b/panel/lxqtpanelapplication.cpp index 507163221..a3d2132f1 100644 --- a/panel/lxqtpanelapplication.cpp +++ b/panel/lxqtpanelapplication.cpp @@ -107,6 +107,8 @@ LXQtPanelApplication::LXQtPanelApplication(int& argc, char** argv) QCoreApplication::setApplicationVersion(VERINFO); + QGuiApplication::setDesktopFileName(QLatin1String("lxqt-panel")); + QCommandLineParser parser; parser.setApplicationDescription(QLatin1String("LXQt Panel")); parser.addHelpOption(); From 5b54478a28a0d0b6c9b7c511053b74c9205d95f8 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Thu, 22 Feb 2024 18:01:49 +0100 Subject: [PATCH 80/92] LXQtTaskbarWaylandBackend: return only accepted windows - reloadWindows() force removal and readding of windows This fixes changing windows grouping settings and adding taskbar plugin AFTER panel is started. Both situations resulted in empty taskbar previously --- .../wayland/lxqttaskbarbackendwayland.cpp | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/panel/backends/wayland/lxqttaskbarbackendwayland.cpp b/panel/backends/wayland/lxqttaskbarbackendwayland.cpp index 57b77c906..27e6b97e5 100644 --- a/panel/backends/wayland/lxqttaskbarbackendwayland.cpp +++ b/panel/backends/wayland/lxqttaskbarbackendwayland.cpp @@ -97,15 +97,30 @@ bool LXQtTaskbarWaylandBackend::supportsAction(WId windowId, LXQtTaskBarBackendA bool LXQtTaskbarWaylandBackend::reloadWindows() { - return false; //TODO + const QVector wids = getCurrentWindows(); + + // Force removal and re-adding + for(WId windowId : wids) + { + emit windowRemoved(windowId); + } + for(WId windowId : wids) + { + emit windowAdded(windowId); + } + + return true; } QVector LXQtTaskbarWaylandBackend::getCurrentWindows() const { - QVector wids(windows.size()); - for(const auto& window : std::as_const(windows)) + QVector wids; + wids.reserve(wids.size()); + + for(const std::unique_ptr& window : std::as_const(windows)) { - wids << window->getWindowId(); + if(window->acceptedInTaskBar) + wids << window->getWindowId(); } return wids; } From 9d024fb1b1ca603e589d8200e148bad7499ff2ac Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Thu, 22 Feb 2024 22:37:49 +0100 Subject: [PATCH 81/92] LXQtPanel: fix auto-hide on Wayland --- panel/lxqtpanel.cpp | 52 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/panel/lxqtpanel.cpp b/panel/lxqtpanel.cpp index 336f1f4cd..dfb91b3fa 100644 --- a/panel/lxqtpanel.cpp +++ b/panel/lxqtpanel.cpp @@ -677,6 +677,37 @@ void LXQtPanel::setPanelGeometry(bool animate) setGeometry(rect); } } + + if(mLayerWindow) + { + // Emulate auto-hide on Wayland + // NOTE: we cannot move window out of screen so we make it smaller + + // NOTE: a cleaner approach would be to use screen edge protocol + // but it's specific to KWin + + if(mHidden && LXQtPanelWidget->isVisible()) + { + // Make it blank + LXQtPanelWidget->hide(); + + // And make it small + if(isHorizontal()) + resize(rect.width(), PANEL_HIDE_SIZE); + else + resize(PANEL_HIDE_SIZE, rect.height()); + } + else if(!mHidden && !LXQtPanelWidget->isVisible()) + { + // Restore contents + LXQtPanelWidget->show(); + + // And make it big again + resize(rect.size()); + } + + updateWmStrut(); + } } void LXQtPanel::setMargins() @@ -804,34 +835,37 @@ void LXQtPanel::updateWmStrut() if (mReserveSpace) { + LayerShellQt::Window::Anchor edge; + switch (mPosition) { case LXQtPanel::PositionTop: - mLayerWindow->setExclusiveEdge(LayerShellQt::Window::AnchorTop); - mLayerWindow->setExclusiveZone(height()); + edge = LayerShellQt::Window::AnchorTop; break; case LXQtPanel::PositionBottom: - mLayerWindow->setExclusiveEdge(LayerShellQt::Window::AnchorBottom); - mLayerWindow->setExclusiveZone(height()); + edge = LayerShellQt::Window::AnchorBottom; break; case LXQtPanel::PositionLeft: - mLayerWindow->setExclusiveEdge(LayerShellQt::Window::AnchorLeft); - mLayerWindow->setExclusiveZone(width()); + edge = LayerShellQt::Window::AnchorLeft; break; case LXQtPanel::PositionRight: - mLayerWindow->setExclusiveEdge(LayerShellQt::Window::AnchorRight); - mLayerWindow->setExclusiveZone(width()); + edge = LayerShellQt::Window::AnchorRight; break; } - } else + + mLayerWindow->setExclusiveEdge(edge); + mLayerWindow->setExclusiveZone(getReserveDimension()); + } + else { mLayerWindow->setExclusiveEdge(LayerShellQt::Window::AnchorNone); mLayerWindow->setExclusiveZone(0); } + // Make LayerShell apply changes immediatly windowHandle()->requestUpdate(); } } From e88c5b26ab637e8fa3c847e33ddac4d6978f5aab Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 23 Feb 2024 12:27:57 +0100 Subject: [PATCH 82/92] LXQtTaskbarWaylandBackend: fix workspace logic --- .../wayland/lxqtplasmavirtualdesktop.cpp | 31 ++++++++++++++----- .../wayland/lxqtplasmavirtualdesktop.h | 8 +++-- .../wayland/lxqttaskbarbackendwayland.cpp | 20 ++++++++---- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/panel/backends/wayland/lxqtplasmavirtualdesktop.cpp b/panel/backends/wayland/lxqtplasmavirtualdesktop.cpp index a3d987f06..fe3d3a435 100644 --- a/panel/backends/wayland/lxqtplasmavirtualdesktop.cpp +++ b/panel/backends/wayland/lxqtplasmavirtualdesktop.cpp @@ -16,6 +16,7 @@ LXQtPlasmaVirtualDesktop::~LXQtPlasmaVirtualDesktop() void LXQtPlasmaVirtualDesktop::org_kde_plasma_virtual_desktop_name(const QString &name) { this->name = name; + Q_EMIT nameChanged(); } void LXQtPlasmaVirtualDesktop::org_kde_plasma_virtual_desktop_done() @@ -73,6 +74,20 @@ LXQtPlasmaWaylandWorkspaceInfo::VirtualDesktopsIterator LXQtPlasmaWaylandWorkspa }); } +QString LXQtPlasmaWaylandWorkspaceInfo::getDesktopName(int pos) const +{ + if(pos < 0 || pos >= virtualDesktops.size()) + return QString(); + return virtualDesktops[pos]->name; +} + +QString LXQtPlasmaWaylandWorkspaceInfo::getDesktopId(int pos) const +{ + if(pos < 0 || pos >= virtualDesktops.size()) + return QString(); + return virtualDesktops[pos]->id; +} + void LXQtPlasmaWaylandWorkspaceInfo::init() { virtualDesktopManagement = std::make_unique(); @@ -86,7 +101,6 @@ void LXQtPlasmaWaylandWorkspaceInfo::init() Q_EMIT numberOfDesktopsChanged(); Q_EMIT navigationWrappingAroundChanged(); Q_EMIT desktopIdsChanged(); - Q_EMIT desktopNamesChanged(); Q_EMIT desktopLayoutRowsChanged(); } }); @@ -105,7 +119,6 @@ void LXQtPlasmaWaylandWorkspaceInfo::init() Q_EMIT numberOfDesktopsChanged(); Q_EMIT desktopIdsChanged(); - Q_EMIT desktopNamesChanged(); if (currentVirtualDesktop == id) { currentVirtualDesktop.clear(); @@ -119,7 +132,7 @@ void LXQtPlasmaWaylandWorkspaceInfo::init() }); } -void LXQtPlasmaWaylandWorkspaceInfo::addDesktop(const QString &id, quint32 position) +void LXQtPlasmaWaylandWorkspaceInfo::addDesktop(const QString &id, quint32 pos) { if (findDesktop(id) != virtualDesktops.end()) { return; @@ -132,15 +145,19 @@ void LXQtPlasmaWaylandWorkspaceInfo::addDesktop(const QString &id, quint32 posit Q_EMIT currentDesktopChanged(); }); - connect(desktop.get(), &LXQtPlasmaVirtualDesktop::done, this, [this]() { - Q_EMIT desktopNamesChanged(); + connect(desktop.get(), &LXQtPlasmaVirtualDesktop::nameChanged, this, [id, this]() { + Q_EMIT desktopNameChanged(position(id)); + }); + + connect(desktop.get(), &LXQtPlasmaVirtualDesktop::done, this, [id, this]() { + Q_EMIT desktopNameChanged(position(id)); }); - virtualDesktops.insert(std::next(virtualDesktops.begin(), position), std::move(desktop)); + virtualDesktops.insert(std::next(virtualDesktops.begin(), pos), std::move(desktop)); Q_EMIT numberOfDesktopsChanged(); Q_EMIT desktopIdsChanged(); - Q_EMIT desktopNamesChanged(); + Q_EMIT desktopNameChanged(position(id)); } QVariant LXQtPlasmaWaylandWorkspaceInfo::currentDesktop() const diff --git a/panel/backends/wayland/lxqtplasmavirtualdesktop.h b/panel/backends/wayland/lxqtplasmavirtualdesktop.h index 3dabb6242..fff025213 100644 --- a/panel/backends/wayland/lxqtplasmavirtualdesktop.h +++ b/panel/backends/wayland/lxqtplasmavirtualdesktop.h @@ -19,6 +19,7 @@ class LXQtPlasmaVirtualDesktop : public QObject, public QtWayland::org_kde_plasm Q_SIGNALS: void done(); void activated(); + void nameChanged(); protected: void org_kde_plasma_virtual_desktop_name(const QString &name) override; @@ -63,8 +64,11 @@ class Q_DECL_HIDDEN LXQtPlasmaWaylandWorkspaceInfo : public QObject VirtualDesktopsIterator findDesktop(const QString &id) const; + QString getDesktopName(int pos) const; + QString getDesktopId(int pos) const; + void init(); - void addDesktop(const QString &id, quint32 position); + void addDesktop(const QString &id, quint32 pos); QVariant currentDesktop() const; int numberOfDesktops() const; QVariantList desktopIds() const; @@ -80,7 +84,7 @@ class Q_DECL_HIDDEN LXQtPlasmaWaylandWorkspaceInfo : public QObject void numberOfDesktopsChanged(); void navigationWrappingAroundChanged(); void desktopIdsChanged(); - void desktopNamesChanged(); + void desktopNameChanged(quint32 position); void desktopLayoutRowsChanged(); }; diff --git a/panel/backends/wayland/lxqttaskbarbackendwayland.cpp b/panel/backends/wayland/lxqttaskbarbackendwayland.cpp index 27e6b97e5..8aa214c65 100644 --- a/panel/backends/wayland/lxqttaskbarbackendwayland.cpp +++ b/panel/backends/wayland/lxqttaskbarbackendwayland.cpp @@ -45,13 +45,17 @@ LXQtTaskbarWaylandBackend::LXQtTaskbarWaylandBackend(QObject *parent) : connect(m_workspaceInfo.get(), &LXQtPlasmaWaylandWorkspaceInfo::currentDesktopChanged, this, [this](){ int idx = m_workspaceInfo->position(m_workspaceInfo->currentDesktop()); + idx += 1; // Make 1-based emit currentWorkspaceChanged(idx); }); connect(m_workspaceInfo.get(), &LXQtPlasmaWaylandWorkspaceInfo::numberOfDesktopsChanged, this, &ILXQtTaskbarAbstractBackend::workspacesCountChanged); - //TODO: connect name changed + connect(m_workspaceInfo.get(), &LXQtPlasmaWaylandWorkspaceInfo::desktopNameChanged, + this, [this](int idx) { + emit workspaceNameChanged(idx + 1); // Make 1-based + }); } bool LXQtTaskbarWaylandBackend::supportsAction(WId windowId, LXQtTaskBarBackendAction action) const @@ -324,19 +328,23 @@ int LXQtTaskbarWaylandBackend::getWorkspacesCount() const QString LXQtTaskbarWaylandBackend::getWorkspaceName(int idx) const { - //TODO: optimize - return m_workspaceInfo->desktopNames().value(idx, QStringLiteral("ERROR")); + return m_workspaceInfo->getDesktopName(idx - 1); //Return to 0-based } int LXQtTaskbarWaylandBackend::getCurrentWorkspace() const { - return 0; //TODO + if(!m_workspaceInfo->currentDesktop().isValid()) + return 0; + return m_workspaceInfo->position(m_workspaceInfo->currentDesktop()) + 1; // 1-based } bool LXQtTaskbarWaylandBackend::setCurrentWorkspace(int idx) { - Q_UNUSED(idx) - return false; //TODO + QString id = m_workspaceInfo->getDesktopId(idx - 1); + if(id.isEmpty()) + return false; + m_workspaceInfo->requestActivate(id); + return true; } int LXQtTaskbarWaylandBackend::getWindowWorkspace(WId windowId) const From a0c1cf8391da798f12b52fc214d2394f82c2179c Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 23 Feb 2024 12:58:54 +0100 Subject: [PATCH 83/92] LXQtTaskbarWaylandBackend: fix workspace removal logic --- panel/backends/wayland/lxqtplasmavirtualdesktop.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/panel/backends/wayland/lxqtplasmavirtualdesktop.cpp b/panel/backends/wayland/lxqtplasmavirtualdesktop.cpp index fe3d3a435..b3e49a681 100644 --- a/panel/backends/wayland/lxqtplasmavirtualdesktop.cpp +++ b/panel/backends/wayland/lxqtplasmavirtualdesktop.cpp @@ -111,11 +111,12 @@ void LXQtPlasmaWaylandWorkspaceInfo::init() connect(virtualDesktopManagement.get(), &LXQtPlasmaVirtualDesktopManagment::desktopRemoved, this, [this](const QString &id) { - std::remove_if(virtualDesktops.begin(), virtualDesktops.end(), - [id](const std::unique_ptr &desktop) - { - return desktop->id == id; - }); + virtualDesktops.erase(std::remove_if(virtualDesktops.begin(), virtualDesktops.end(), + [id](const std::unique_ptr &desktop) + { + return desktop->id == id; + }), + virtualDesktops.end()); Q_EMIT numberOfDesktopsChanged(); Q_EMIT desktopIdsChanged(); From 30e96c211cb4f876d22e5dbfb31d071a050e1722 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 23 Feb 2024 13:33:40 +0100 Subject: [PATCH 84/92] lxqttaskbartypes.h: fix ShowOnAll desktops flag value --- panel/backends/lxqttaskbartypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panel/backends/lxqttaskbartypes.h b/panel/backends/lxqttaskbartypes.h index 9e12092bb..ae3d5f107 100644 --- a/panel/backends/lxqttaskbartypes.h +++ b/panel/backends/lxqttaskbartypes.h @@ -49,7 +49,7 @@ enum class LXQtTaskBarWindowLayer enum class LXQtTaskBarWorkspace { - ShowOnAll = -1 + ShowOnAll = 0 // Virtual destops have 1-based indexes }; #endif // LXQTTASKBARTYPES_H From 90eb2df9d195923f59902fbc9ced240418939512 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Fri, 23 Feb 2024 13:34:16 +0100 Subject: [PATCH 85/92] LXQtTaskbarWaylandBackend: implement moving window to virtual desktop workspace --- .../wayland/lxqttaskbarbackendwayland.cpp | 51 ++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/panel/backends/wayland/lxqttaskbarbackendwayland.cpp b/panel/backends/wayland/lxqttaskbarbackendwayland.cpp index 8aa214c65..fb6e940a8 100644 --- a/panel/backends/wayland/lxqttaskbarbackendwayland.cpp +++ b/panel/backends/wayland/lxqttaskbarbackendwayland.cpp @@ -340,7 +340,7 @@ int LXQtTaskbarWaylandBackend::getCurrentWorkspace() const bool LXQtTaskbarWaylandBackend::setCurrentWorkspace(int idx) { - QString id = m_workspaceInfo->getDesktopId(idx - 1); + QString id = m_workspaceInfo->getDesktopId(idx - 1); //Return to 0-based if(id.isEmpty()) return false; m_workspaceInfo->requestActivate(id); @@ -349,15 +349,54 @@ bool LXQtTaskbarWaylandBackend::setCurrentWorkspace(int idx) int LXQtTaskbarWaylandBackend::getWindowWorkspace(WId windowId) const { - Q_UNUSED(windowId) - return 0; //TODO + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return 0; + + // TODO: this protocol seems to allow multiple desktop for each window + // We do not support that yet + // Also from KDE Plasma task switch it's not clear how to actually put + // a window on multiple desktops (which is different from "All desktops") + QString id = window->virtualDesktops.value(0, QString()); + if(id.isEmpty()) + return 0; + + return m_workspaceInfo->position(id) + 1; //Make 1-based } bool LXQtTaskbarWaylandBackend::setWindowOnWorkspace(WId windowId, int idx) { - Q_UNUSED(windowId) - Q_UNUSED(idx) - return false; //TODO + LXQtTaskBarPlasmaWindow *window = getWindow(windowId); + if(!window) + return false; + + // Prepare for future multiple virtual desktops per window + QList newDesktops; + + // Fill the list + newDesktops.append(m_workspaceInfo->getDesktopId(idx - 1)); //Return to 0-based + + // Keep only valid IDs + newDesktops.erase(std::remove_if(newDesktops.begin(), newDesktops.end(), + [](const QString& id) { return id.isEmpty(); }), + newDesktops.end()); + + // Add to new requested desktops + for(const QString& id : std::as_const(newDesktops)) + { + if(!window->virtualDesktops.contains(id)) + window->request_enter_virtual_desktop(id); + } + + // Remove from non-requested destops + const QList currentDesktops = window->virtualDesktops; + for(const QString& id : std::as_const(currentDesktops)) + { + if(!newDesktops.contains(id)) + window->request_leave_virtual_desktop(id); + } + + return true; } void LXQtTaskbarWaylandBackend::moveApplicationToPrevNextMonitor(WId windowId, bool next, bool raiseOnCurrentDesktop) From f29cf3a61eaa211e534685cd908379d2ca6510f0 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Mon, 26 Feb 2024 09:48:03 +0100 Subject: [PATCH 86/92] ColorPicker: use XDG Desktop Portal on Wayland TODO TODO: show error message when not supported --- plugin-colorpicker/colorpicker.cpp | 156 ++++++++++++++++++++++++++--- plugin-colorpicker/colorpicker.h | 8 ++ 2 files changed, 150 insertions(+), 14 deletions(-) diff --git a/plugin-colorpicker/colorpicker.cpp b/plugin-colorpicker/colorpicker.cpp index 004314557..0827686d5 100644 --- a/plugin-colorpicker/colorpicker.cpp +++ b/plugin-colorpicker/colorpicker.cpp @@ -36,6 +36,9 @@ #include #include +#include +#include + //NOTE: Xlib.h defines Bool which conflicts with QJsonValue::Type enum #include #undef Bool @@ -77,6 +80,33 @@ void ColorPicker::realign() mWidget.update(panel()->lineCount() <= 1 ? panel()->isHorizontal() : !panel()->isHorizontal()); } +void ColorPicker::queryXDGSupport() +{ + if (qEnvironmentVariableIntValue("QT_NO_XDG_DESKTOP_PORTAL") > 0) { + return; + } + QDBusMessage message = QDBusMessage::createMethodCall( + QLatin1String("org.freedesktop.portal.Desktop"), + QLatin1String("/org/freedesktop/portal/desktop"), + QLatin1String("org.freedesktop.DBus.Properties"), + QLatin1String("Get")); + message << QLatin1String("org.freedesktop.portal.Screenshot") + << QLatin1String("version"); + + QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message); + auto watcher = new QDBusPendingCallWatcher(pendingCall); + QObject::connect(watcher, &QDBusPendingCallWatcher::finished, watcher, + [this](QDBusPendingCallWatcher *watcher) { + watcher->deleteLater(); + QDBusPendingReply reply = *watcher; + if (!reply.isError() && reply.value().toUInt() >= 2) + m_hasScreenshotPortalWithColorPicking = true; + }); + + //TODO: show error tooltip if not supported + //NOTE: on Wayland we cannot pick color without it +} + ColorPickerWidget::ColorPickerWidget(QWidget *parent) : QWidget(parent) { @@ -108,7 +138,8 @@ ColorPickerWidget::ColorPickerWidget(QWidget *parent) : QWidget(parent) layout->addWidget(mColorButton); setLayout(layout); - connect(mPickerButton, &QToolButton::clicked, this, &ColorPickerWidget::captureMouse); + connect(mPickerButton, &QToolButton::clicked, this, &ColorPickerWidget::startCapturingColor); + connect(mColorButton, &QToolButton::clicked, this, [&]() { buildMenu(); @@ -162,29 +193,86 @@ void ColorPickerWidget::mouseReleaseEvent(QMouseEvent *event) qWarning() << "WAYLAND does not support grabbing windows"; } - mColorButton->setColor(col); - paste(col.name()); + setCapturedColor(col); - if (mColorsList.contains(col)) + mCapturing = false; + releaseMouse(); + + if (!mPickerButton->contentsRect().contains(mapFromGlobal(QCursor::pos()))) { - mColorsList.move(mColorsList.indexOf(col), 0); + QApplication::sendEvent(mPickerButton, new QEvent(QEvent::Leave)); } - else +} + +void ColorPickerWidget::startCapturingColor() +{ + //NOTE: see qt6 `src/gui/platform/unix/qgenericunixservices.cpp` + + // Make double sure that we are in a wayland environment. In particular check + // WAYLAND_DISPLAY so also XWayland apps benefit from portal-based color picking. + // Outside wayland we'll rather rely on other means than the XDG desktop portal. + if (!qEnvironmentVariableIsEmpty("WAYLAND_DISPLAY") + || QGuiApplication::platformName().startsWith(QLatin1String("wayland"))) { - mColorsList.prepend(col); + // On Wayland use XDG Desktop Portal + + QString m_parentWindowId; //TODO + + QDBusMessage message = QDBusMessage::createMethodCall( + QLatin1String("org.freedesktop.portal.Desktop"), + QLatin1String("/org/freedesktop/portal/desktop"), + QLatin1String("org.freedesktop.portal.Screenshot"), + QLatin1String("PickColor")); + message << m_parentWindowId << QVariantMap(); + + QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message); + auto watcher = new QDBusPendingCallWatcher(pendingCall, this); + connect(watcher, &QDBusPendingCallWatcher::finished, this, + [this](QDBusPendingCallWatcher *watcher) { + watcher->deleteLater(); + QDBusPendingReply reply = *watcher; + if (reply.isError()) { + qWarning("DBus call to pick color failed: %s", + qPrintable(reply.error().message())); + setCapturedColor({}); + } else { + QDBusConnection::sessionBus().connect( + QLatin1String("org.freedesktop.portal.Desktop"), + reply.value().path(), + QLatin1String("org.freedesktop.portal.Request"), + QLatin1String("Response"), + this, + // clang-format off + SLOT(gotColorResponse(uint,QVariantMap)) + // clang-format on + ); + } + }); } - - if (mColorsList.size() > 10) + else if (qGuiApp->nativeInterface()) { - mColorsList.removeLast(); + // On X11 grab mouse and let `mouseReleaseEvent()` retrieve color + captureMouse(); } +} - mCapturing = false; - releaseMouse(); +void ColorPickerWidget::setCapturedColor(const QColor &color) +{ + mColorButton->setColor(color); + paste(color.name()); - if (!mPickerButton->contentsRect().contains(mapFromGlobal(QCursor::pos()))) + if (mColorsList.contains(color)) { - QApplication::sendEvent(mPickerButton, new QEvent(QEvent::Leave)); + mColorsList.move(mColorsList.indexOf(color), 0); + } + else + { + mColorsList.prepend(color); + } + + if (mColorsList.size() > 10) + { + mColorsList.removeLast(); } } @@ -195,6 +283,46 @@ void ColorPickerWidget::captureMouse() mCapturing = true; } +struct XDGDesktopColor +{ + double r = 0; + double g = 0; + double b = 0; + + QColor toQColor() const + { + constexpr auto rgbMax = 255; + return { static_cast(r * rgbMax), static_cast(g * rgbMax), + static_cast(b * rgbMax) }; + } +}; + +const QDBusArgument &operator>>(const QDBusArgument &argument, XDGDesktopColor &myStruct) +{ + argument.beginStructure(); + argument >> myStruct.r >> myStruct.g >> myStruct.b; + argument.endStructure(); + return argument; +} + +void ColorPickerWidget::gotColorResponse(uint result, const QVariantMap &map) +{ + auto colorProp = QStringLiteral("color"); + + if (result != 0) + return; + if (map.contains(colorProp)) + { + XDGDesktopColor color{}; + map.value(colorProp).value() >> color; + setCapturedColor(color.toQColor()); + } + else + { + setCapturedColor({}); + } +} + QIcon ColorPickerWidget::colorIcon(QColor color) { diff --git a/plugin-colorpicker/colorpicker.h b/plugin-colorpicker/colorpicker.h index 919f42490..ecf2a3b41 100644 --- a/plugin-colorpicker/colorpicker.h +++ b/plugin-colorpicker/colorpicker.h @@ -58,7 +58,10 @@ class ColorPickerWidget : public QWidget void mouseReleaseEvent(QMouseEvent *event); private slots: + void startCapturingColor(); + void setCapturedColor(const QColor& color); void captureMouse(); + void gotColorResponse(uint result, const QVariantMap& map); private: static const QString svgIcon; @@ -91,8 +94,13 @@ class ColorPicker : public QObject, public ILXQtPanelPlugin virtual void realign() override; +private: + void queryXDGSupport(); + private: ColorPickerWidget mWidget; + + bool m_hasScreenshotPortalWithColorPicking = false; }; class ColorPickerLibrary: public QObject, public ILXQtPanelPluginLibrary From fc398ba5e35feeb096c44a467894a09bd105833f Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Wed, 28 Feb 2024 20:43:50 +0100 Subject: [PATCH 87/92] LXQtPlasmaWaylandWorkspaceInfo: fix signedness comparison --- panel/backends/wayland/lxqtplasmavirtualdesktop.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/panel/backends/wayland/lxqtplasmavirtualdesktop.cpp b/panel/backends/wayland/lxqtplasmavirtualdesktop.cpp index b3e49a681..01e28fe75 100644 --- a/panel/backends/wayland/lxqtplasmavirtualdesktop.cpp +++ b/panel/backends/wayland/lxqtplasmavirtualdesktop.cpp @@ -76,14 +76,14 @@ LXQtPlasmaWaylandWorkspaceInfo::VirtualDesktopsIterator LXQtPlasmaWaylandWorkspa QString LXQtPlasmaWaylandWorkspaceInfo::getDesktopName(int pos) const { - if(pos < 0 || pos >= virtualDesktops.size()) + if(pos < 0 || size_t(pos) >= virtualDesktops.size()) return QString(); return virtualDesktops[pos]->name; } QString LXQtPlasmaWaylandWorkspaceInfo::getDesktopId(int pos) const { - if(pos < 0 || pos >= virtualDesktops.size()) + if(pos < 0 || size_t(pos) >= virtualDesktops.size()) return QString(); return virtualDesktops[pos]->id; } From f6e9ba92146b142d4846304cf8390f4bd71cd70f Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Thu, 29 Feb 2024 00:09:55 +0100 Subject: [PATCH 88/92] CMake: move panel WM backends to separate libraries - QTime is included to fix build errors --- panel/CMakeLists.txt | 47 +++---------------- panel/backends/CMakeLists.txt | 17 +++++++ .../backends/ilxqttaskbarabstractbackend.cpp | 2 +- panel/backends/wayland/CMakeLists.txt | 31 ++++++++++++ .../wayland/lxqtplasmavirtualdesktop.h | 1 + .../lxqttaskbarplasmawindowmanagment.cpp | 2 - panel/backends/xcb/CMakeLists.txt | 13 +++++ 7 files changed, 70 insertions(+), 43 deletions(-) diff --git a/panel/CMakeLists.txt b/panel/CMakeLists.txt index d1008d561..ef1291af5 100644 --- a/panel/CMakeLists.txt +++ b/panel/CMakeLists.txt @@ -1,10 +1,13 @@ set(PROJECT lxqt-panel) -# TODO +# Window Manager abstraction backend add_subdirectory(backends) -# TODO: move to backend folder -find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS WaylandClient Concurrent) +# TODO: allow compile time selection via CMake variables +set(PANEL_BACKENDS + lxqt-panel-backend-wayland + lxqt-panel-backend-xcb +) set(PRIV_HEADERS @@ -25,17 +28,6 @@ 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 - - backends/wayland/lxqttaskbarbackendwayland.h - backends/wayland/lxqttaskbarplasmawindowmanagment.h - backends/wayland/lxqtplasmavirtualdesktop.h ) # using LXQt namespace in the public headers. @@ -44,9 +36,6 @@ set(PUB_HEADERS pluginsettings.h ilxqtpanelplugin.h ilxqtpanel.h - - backends/ilxqttaskbarabstractbackend.h - backends/lxqttaskbartypes.h ) set(SOURCES @@ -66,16 +55,6 @@ set(SOURCES config/configstyling.cpp config/configpluginswidget.cpp config/addplugindialog.cpp - - backends/ilxqttaskbarabstractbackend.cpp - - backends/lxqttaskbardummybackend.cpp - - backends/xcb/lxqttaskbarbackend_x11.cpp - - backends/wayland/lxqttaskbarbackendwayland.cpp - backends/wayland/lxqttaskbarplasmawindowmanagment.cpp - backends/wayland/lxqtplasmavirtualdesktop.cpp ) set(UI @@ -130,23 +109,11 @@ add_executable(${PROJECT} ${UI} ) -# TODO: move to backend folder -qt6_generate_wayland_protocol_client_sources(${PROJECT} -FILES - ${CMAKE_CURRENT_SOURCE_DIR}/backends/wayland/protocols/plasma-window-management.xml -) - -qt6_generate_wayland_protocol_client_sources(${PROJECT} -FILES - ${CMAKE_CURRENT_SOURCE_DIR}/backends/wayland/protocols/org-kde-plasma-virtual-desktop.xml -) - target_link_libraries(${PROJECT} ${LIBRARIES} ${QTX_LIBRARIES} KF6::WindowSystem - Qt6::WaylandClient # TODO: Move to backend folder - Qt6::Concurrent + ${PANEL_BACKENDS} LayerShellQt::Interface ${STATIC_PLUGINS} ) diff --git a/panel/backends/CMakeLists.txt b/panel/backends/CMakeLists.txt index f1915b823..c369eb81f 100644 --- a/panel/backends/CMakeLists.txt +++ b/panel/backends/CMakeLists.txt @@ -1,2 +1,19 @@ +# Common interface for Window Manager abstraction backend +# This also contains dummy backend + +add_library(lxqt-panel-backend-common STATIC + + lxqttaskbartypes.h + ilxqttaskbarabstractbackend.h + ilxqttaskbarabstractbackend.cpp + + lxqttaskbardummybackend.h + lxqttaskbardummybackend.cpp +) + +target_link_libraries(lxqt-panel-backend-common + Qt6::Gui +) + add_subdirectory(wayland) add_subdirectory(xcb) diff --git a/panel/backends/ilxqttaskbarabstractbackend.cpp b/panel/backends/ilxqttaskbarabstractbackend.cpp index 137728263..dbad943d5 100644 --- a/panel/backends/ilxqttaskbarabstractbackend.cpp +++ b/panel/backends/ilxqttaskbarabstractbackend.cpp @@ -1,4 +1,4 @@ -#include "../panel/backends/ilxqttaskbarabstractbackend.h" +#include "ilxqttaskbarabstractbackend.h" ILXQtTaskbarAbstractBackend::ILXQtTaskbarAbstractBackend(QObject *parent) diff --git a/panel/backends/wayland/CMakeLists.txt b/panel/backends/wayland/CMakeLists.txt index 8b1378917..e0ecab6e9 100644 --- a/panel/backends/wayland/CMakeLists.txt +++ b/panel/backends/wayland/CMakeLists.txt @@ -1 +1,32 @@ +# Wayland WM Backend +project(lxqt-panel-backend-wayland) + +find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS WaylandClient Concurrent) + +add_library(lxqt-panel-backend-wayland STATIC + lxqttaskbarbackendwayland.h + lxqttaskbarplasmawindowmanagment.h + lxqtplasmavirtualdesktop.h + + lxqttaskbarbackendwayland.cpp + lxqttaskbarplasmawindowmanagment.cpp + lxqtplasmavirtualdesktop.cpp +) + +qt6_generate_wayland_protocol_client_sources(lxqt-panel-backend-wayland +FILES + ${CMAKE_CURRENT_SOURCE_DIR}/protocols/plasma-window-management.xml +) + +qt6_generate_wayland_protocol_client_sources(lxqt-panel-backend-wayland +FILES + ${CMAKE_CURRENT_SOURCE_DIR}/protocols/org-kde-plasma-virtual-desktop.xml +) + +target_link_libraries(lxqt-panel-backend-wayland + Qt6::GuiPrivate + Qt6::WaylandClient + Qt6::Concurrent + lxqt-panel-backend-common +) diff --git a/panel/backends/wayland/lxqtplasmavirtualdesktop.h b/panel/backends/wayland/lxqtplasmavirtualdesktop.h index fff025213..65324e013 100644 --- a/panel/backends/wayland/lxqtplasmavirtualdesktop.h +++ b/panel/backends/wayland/lxqtplasmavirtualdesktop.h @@ -1,6 +1,7 @@ #ifndef LXQTPLASMAVIRTUALDESKTOP_H #define LXQTPLASMAVIRTUALDESKTOP_H +#include // TODO: needed to fix compile errors about QHashPrivate #include #include diff --git a/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp b/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp index f813181ed..b4339dbb0 100644 --- a/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp +++ b/panel/backends/wayland/lxqttaskbarplasmawindowmanagment.cpp @@ -1,7 +1,5 @@ #include "lxqttaskbarplasmawindowmanagment.h" -#include - #include #include #include diff --git a/panel/backends/xcb/CMakeLists.txt b/panel/backends/xcb/CMakeLists.txt index 8b1378917..ad36ccaa3 100644 --- a/panel/backends/xcb/CMakeLists.txt +++ b/panel/backends/xcb/CMakeLists.txt @@ -1 +1,14 @@ +# XCB WM Backend + +project(lxqt-panel-backend-xcb) + +add_library(lxqt-panel-backend-xcb STATIC + lxqttaskbarbackend_x11.h + lxqttaskbarbackend_x11.cpp +) + +target_link_libraries(lxqt-panel-backend-xcb + KF6::WindowSystem + lxqt-panel-backend-common +) From 06a6eeda9d803e156e5c855ef5c02adffbdeddd3 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Thu, 29 Feb 2024 10:50:31 +0100 Subject: [PATCH 89/92] LXQtTaskbarWaylandBackend: fix QTime inclusion TODO Now it's fixed corretly TODO: merge with previous commit --- panel/backends/wayland/lxqtplasmavirtualdesktop.h | 1 - panel/backends/wayland/lxqttaskbarbackendwayland.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/panel/backends/wayland/lxqtplasmavirtualdesktop.h b/panel/backends/wayland/lxqtplasmavirtualdesktop.h index 65324e013..fff025213 100644 --- a/panel/backends/wayland/lxqtplasmavirtualdesktop.h +++ b/panel/backends/wayland/lxqtplasmavirtualdesktop.h @@ -1,7 +1,6 @@ #ifndef LXQTPLASMAVIRTUALDESKTOP_H #define LXQTPLASMAVIRTUALDESKTOP_H -#include // TODO: needed to fix compile errors about QHashPrivate #include #include diff --git a/panel/backends/wayland/lxqttaskbarbackendwayland.h b/panel/backends/wayland/lxqttaskbarbackendwayland.h index 0b12ef2fd..df202f076 100644 --- a/panel/backends/wayland/lxqttaskbarbackendwayland.h +++ b/panel/backends/wayland/lxqttaskbarbackendwayland.h @@ -3,6 +3,7 @@ #include "../ilxqttaskbarabstractbackend.h" +#include #include #include From a24d88a9c1ee97e6fdd8ebcdfe8cbf34e4e759fe Mon Sep 17 00:00:00 2001 From: redtide Date: Thu, 29 Feb 2024 14:41:35 +0100 Subject: [PATCH 90/92] CI: LXQt2 test --- .ci/build.sh | 9 ----- .ci/install.sh | 71 ++++++++++++++++++++++++++++++++++++++ .github/workflows/test.yml | 18 +++++----- 3 files changed, 81 insertions(+), 17 deletions(-) delete mode 100755 .ci/build.sh create mode 100755 .ci/install.sh diff --git a/.ci/build.sh b/.ci/build.sh deleted file mode 100755 index 9c2e643b0..000000000 --- a/.ci/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -set -ex - -source shared-ci/prepare-archlinux.sh - -# See *depends in https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=lxqt-panel-git -pacman -S --noconfirm --needed git cmake qt5-tools lxqt-build-tools-git alsa-lib libpulse lm_sensors libstatgrab libsysstat-git solid5 menu-cache libxcomposite lxqt-menu-data-git libdbusmenu-qt5 lxqt-globalkeys-git libxtst - -cmake -B build -S . -make -C build diff --git a/.ci/install.sh b/.ci/install.sh new file mode 100755 index 000000000..87ffc39e4 --- /dev/null +++ b/.ci/install.sh @@ -0,0 +1,71 @@ +set -ex + +#source shared-ci/prepare-archlinux.sh + +cat >> /etc/pacman.conf <> /etc/pacman.conf < Date: Thu, 29 Feb 2024 22:04:16 +0100 Subject: [PATCH 91/92] Remove CI workaround --- .ci/install.sh | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.ci/install.sh b/.ci/install.sh index 87ffc39e4..07fba546e 100755 --- a/.ci/install.sh +++ b/.ci/install.sh @@ -62,10 +62,3 @@ lxqt2wip_packages=( libsysstat-git ) pacman -S --noconfirm ${lxqt2wip_packages[@]} - -# workaround -cd /usr/share/cmake -cp -R lxqt2-menu-data lxqt-menu-data -cd lxqt-menu-data -mv lxqt2-menu-data-config.cmake lxqt-menu-data-config.cmake -mv lxqt2-menu-data-config-version.cmake lxqt-menu-data-config-version.cmake From 794648c58492720328178cb883a8fe070cacbe10 Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Sat, 9 Mar 2024 20:06:15 +0100 Subject: [PATCH 92/92] LXQtPanel: set LayerShellQt KeyboardInteractivityOnDemand Set layer shell keyboard interactivity on-demand --- panel/lxqtpanel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panel/lxqtpanel.cpp b/panel/lxqtpanel.cpp index dfb91b3fa..a7a4508ab 100644 --- a/panel/lxqtpanel.cpp +++ b/panel/lxqtpanel.cpp @@ -251,7 +251,7 @@ LXQtPanel::LXQtPanel(const QString &configGroup, LXQt::Settings *settings, QWidg anchors.setFlag(LayerShellQt::Window::AnchorRight); mLayerWindow->setAnchors(anchors); - mLayerWindow->setKeyboardInteractivity(LayerShellQt::Window::KeyboardInteractivityNone); + mLayerWindow->setKeyboardInteractivity(LayerShellQt::Window::KeyboardInteractivityOnDemand); mLayerWindow->setCloseOnDismissed(false); mLayerWindow->setExclusiveEdge(LayerShellQt::Window::AnchorBottom);