From 0926373b1490613a554691cfe81fe09751cb2bb1 Mon Sep 17 00:00:00 2001 From: Reion Wong Date: Sun, 30 Aug 2026 20:25:25 -0400 Subject: [PATCH] feat(core): migrate services to Wayland --- CMakeLists.txt | 4 - README.md | 30 +- chotkeys/CMakeLists.txt | 26 - chotkeys/application.cpp | 73 -- chotkeys/application.h | 44 -- chotkeys/hotkeys.cpp | 296 -------- chotkeys/hotkeys.h | 63 -- chotkeys/main.cpp | 39 -- cmake/ECMFindModuleHelpers.cmake | 297 -------- cmake/FindX11_XCB.cmake | 92 --- cmake/FindXCB.cmake | 177 ----- cupdatecursor/CMakeLists.txt | 16 - cupdatecursor/main.cpp | 54 -- debian/control | 24 - gmenuproxy/CMakeLists.txt | 53 -- gmenuproxy/actions.cpp | 196 ------ gmenuproxy/actions.h | 44 -- gmenuproxy/com.canonical.dbusmenu.xml | 49 -- gmenuproxy/cutefish-gmenuproxy.service.in | 10 - gmenuproxy/dbusmenuadaptor.cpp | 79 --- gmenuproxy/dbusmenuadaptor.h | 111 --- gmenuproxy/extend/dbusmenushortcut_p.cpp | 69 -- gmenuproxy/extend/dbusmenushortcut_p.h | 22 - gmenuproxy/extend/dbusmenutypes_p.cpp | 122 ---- gmenuproxy/extend/dbusmenutypes_p.h | 80 --- gmenuproxy/gdbusmenutypes_p.cpp | 119 ---- gmenuproxy/gdbusmenutypes_p.h | 89 --- gmenuproxy/gmenudbusmenuproxy.desktop | 50 -- gmenuproxy/icons.cpp | 308 --------- gmenuproxy/icons.h | 15 - gmenuproxy/main.cpp | 37 - gmenuproxy/menu.cpp | 328 --------- gmenuproxy/menu.h | 67 -- gmenuproxy/menuproxy.cpp | 388 ----------- gmenuproxy/menuproxy.h | 63 -- gmenuproxy/utils.cpp | 29 - gmenuproxy/utils.h | 19 - gmenuproxy/window.cpp | 653 ------------------ gmenuproxy/window.h | 127 ---- notificationd/CMakeLists.txt | 3 - notificationd/notificationpopup.cpp | 9 - notificationd/notificationwindow.cpp | 7 - powerman/CMakeLists.txt | 14 - powerman/dimdisplayaction.cpp | 10 - .../com.cutefish.sddm.helper.pkexec.policy.in | 4 +- sddm-helper/main.cpp | 24 +- session/CMakeLists.txt | 4 - session/application.cpp | 103 +-- session/application.h | 7 - session/cutefish-kwin-wayland-session | 2 +- session/cutefish-wayland-session | 2 +- session/cutefish-xsession.desktop | 7 - session/main.cpp | 1 - session/processmanager.cpp | 110 +-- session/processmanager.h | 8 +- settings-daemon/CMakeLists.txt | 19 - settings-daemon/application.cpp | 44 +- settings-daemon/application.h | 4 - settings-daemon/input/kwininputbackend.cpp | 167 +++++ settings-daemon/input/kwininputbackend.h | 51 ++ settings-daemon/mouse/com.cutefish.Mouse.xml | 7 + settings-daemon/mouse/libinputsettings.cpp | 39 -- settings-daemon/mouse/libinputsettings.h | 20 - settings-daemon/mouse/mousemanager.cpp | 77 +-- settings-daemon/mouse/mousemanager.h | 10 +- .../mouse/x11libinputdummydevice.cpp | 242 ------- .../mouse/x11libinputdummydevice.h | 297 -------- settings-daemon/theme/com.cutefish.Theme.xml | 2 +- settings-daemon/theme/thememanager.cpp | 77 +-- settings-daemon/theme/thememanager.h | 4 +- .../touchpad/com.cutefish.Touchpad.xml | 6 + settings-daemon/touchpad/libinputcommon.cpp | 9 - settings-daemon/touchpad/libinputcommon.h | 566 --------------- settings-daemon/touchpad/touchpadmanager.cpp | 52 +- settings-daemon/touchpad/touchpadmanager.h | 22 +- .../touchpad/x11/libinputtouchpad.cpp | 401 ----------- .../touchpad/x11/libinputtouchpad.h | 148 ---- settings-daemon/touchpad/x11/propertyinfo.cpp | 86 --- settings-daemon/touchpad/x11/propertyinfo.h | 37 - .../touchpad/x11/synapticstouchpad.cpp | 225 ------ .../touchpad/x11/synapticstouchpad.h | 34 - settings-daemon/touchpad/x11/xcbatom.cpp | 48 -- settings-daemon/touchpad/x11/xcbatom.h | 36 - settings-daemon/touchpad/x11/xlibbackend.cpp | 425 ------------ settings-daemon/touchpad/x11/xlibbackend.h | 123 ---- .../touchpad/x11/xlibnotifications.cpp | 135 ---- .../touchpad/x11/xlibnotifications.h | 41 -- settings-daemon/touchpad/x11/xlibtouchpad.cpp | 257 ------- settings-daemon/touchpad/x11/xlibtouchpad.h | 101 --- .../touchpad/x11/xrecordkeyboardmonitor.cpp | 140 ---- .../touchpad/x11/xrecordkeyboardmonitor.h | 49 -- shutdown-ui/main.qml | 2 +- x11utils.h | 26 - xembed-sni-proxy/CMakeLists.txt | 80 --- xembed-sni-proxy/debug.cpp | 8 - xembed-sni-proxy/debug.h | 12 - xembed-sni-proxy/fdoselectionmanager.cpp | 234 ------- xembed-sni-proxy/fdoselectionmanager.h | 47 -- xembed-sni-proxy/main.cpp | 60 -- .../org.kde.StatusNotifierItem.xml | 63 -- .../org.kde.StatusNotifierWatcher.xml | 42 -- xembed-sni-proxy/snidbus.cpp | 133 ---- xembed-sni-proxy/snidbus.h | 47 -- xembed-sni-proxy/sniproxy.cpp | 597 ---------------- xembed-sni-proxy/sniproxy.h | 160 ----- xembed-sni-proxy/xcbutils.h | 122 ---- xembed-sni-proxy/xtestsender.cpp | 19 - xembed-sni-proxy/xtestsender.h | 12 - 108 files changed, 397 insertions(+), 9945 deletions(-) delete mode 100644 chotkeys/CMakeLists.txt delete mode 100644 chotkeys/application.cpp delete mode 100644 chotkeys/application.h delete mode 100644 chotkeys/hotkeys.cpp delete mode 100644 chotkeys/hotkeys.h delete mode 100644 chotkeys/main.cpp delete mode 100644 cmake/ECMFindModuleHelpers.cmake delete mode 100644 cmake/FindX11_XCB.cmake delete mode 100644 cmake/FindXCB.cmake delete mode 100644 cupdatecursor/CMakeLists.txt delete mode 100644 cupdatecursor/main.cpp delete mode 100644 gmenuproxy/CMakeLists.txt delete mode 100644 gmenuproxy/actions.cpp delete mode 100644 gmenuproxy/actions.h delete mode 100644 gmenuproxy/com.canonical.dbusmenu.xml delete mode 100644 gmenuproxy/cutefish-gmenuproxy.service.in delete mode 100644 gmenuproxy/dbusmenuadaptor.cpp delete mode 100644 gmenuproxy/dbusmenuadaptor.h delete mode 100644 gmenuproxy/extend/dbusmenushortcut_p.cpp delete mode 100644 gmenuproxy/extend/dbusmenushortcut_p.h delete mode 100644 gmenuproxy/extend/dbusmenutypes_p.cpp delete mode 100644 gmenuproxy/extend/dbusmenutypes_p.h delete mode 100644 gmenuproxy/gdbusmenutypes_p.cpp delete mode 100644 gmenuproxy/gdbusmenutypes_p.h delete mode 100644 gmenuproxy/gmenudbusmenuproxy.desktop delete mode 100644 gmenuproxy/icons.cpp delete mode 100644 gmenuproxy/icons.h delete mode 100644 gmenuproxy/main.cpp delete mode 100644 gmenuproxy/menu.cpp delete mode 100644 gmenuproxy/menu.h delete mode 100644 gmenuproxy/menuproxy.cpp delete mode 100644 gmenuproxy/menuproxy.h delete mode 100644 gmenuproxy/utils.cpp delete mode 100644 gmenuproxy/utils.h delete mode 100644 gmenuproxy/window.cpp delete mode 100644 gmenuproxy/window.h delete mode 100644 session/cutefish-xsession.desktop create mode 100644 settings-daemon/input/kwininputbackend.cpp create mode 100644 settings-daemon/input/kwininputbackend.h delete mode 100644 settings-daemon/mouse/libinputsettings.cpp delete mode 100644 settings-daemon/mouse/libinputsettings.h delete mode 100644 settings-daemon/mouse/x11libinputdummydevice.cpp delete mode 100644 settings-daemon/mouse/x11libinputdummydevice.h delete mode 100644 settings-daemon/touchpad/libinputcommon.cpp delete mode 100644 settings-daemon/touchpad/libinputcommon.h delete mode 100644 settings-daemon/touchpad/x11/libinputtouchpad.cpp delete mode 100644 settings-daemon/touchpad/x11/libinputtouchpad.h delete mode 100644 settings-daemon/touchpad/x11/propertyinfo.cpp delete mode 100644 settings-daemon/touchpad/x11/propertyinfo.h delete mode 100644 settings-daemon/touchpad/x11/synapticstouchpad.cpp delete mode 100644 settings-daemon/touchpad/x11/synapticstouchpad.h delete mode 100644 settings-daemon/touchpad/x11/xcbatom.cpp delete mode 100644 settings-daemon/touchpad/x11/xcbatom.h delete mode 100644 settings-daemon/touchpad/x11/xlibbackend.cpp delete mode 100644 settings-daemon/touchpad/x11/xlibbackend.h delete mode 100644 settings-daemon/touchpad/x11/xlibnotifications.cpp delete mode 100644 settings-daemon/touchpad/x11/xlibnotifications.h delete mode 100644 settings-daemon/touchpad/x11/xlibtouchpad.cpp delete mode 100644 settings-daemon/touchpad/x11/xlibtouchpad.h delete mode 100644 settings-daemon/touchpad/x11/xrecordkeyboardmonitor.cpp delete mode 100644 settings-daemon/touchpad/x11/xrecordkeyboardmonitor.h delete mode 100644 x11utils.h delete mode 100644 xembed-sni-proxy/CMakeLists.txt delete mode 100644 xembed-sni-proxy/debug.cpp delete mode 100644 xembed-sni-proxy/debug.h delete mode 100644 xembed-sni-proxy/fdoselectionmanager.cpp delete mode 100644 xembed-sni-proxy/fdoselectionmanager.h delete mode 100644 xembed-sni-proxy/main.cpp delete mode 100644 xembed-sni-proxy/org.kde.StatusNotifierItem.xml delete mode 100644 xembed-sni-proxy/org.kde.StatusNotifierWatcher.xml delete mode 100644 xembed-sni-proxy/snidbus.cpp delete mode 100644 xembed-sni-proxy/snidbus.h delete mode 100644 xembed-sni-proxy/sniproxy.cpp delete mode 100644 xembed-sni-proxy/sniproxy.h delete mode 100644 xembed-sni-proxy/xcbutils.h delete mode 100644 xembed-sni-proxy/xtestsender.cpp delete mode 100644 xembed-sni-proxy/xtestsender.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 99a7fe7..5b96ec5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,12 +26,8 @@ add_subdirectory(screen-brightness) add_subdirectory(session) add_subdirectory(settings-daemon) add_subdirectory(shutdown-ui) -add_subdirectory(xembed-sni-proxy) add_subdirectory(powerman) add_subdirectory(cpufreq) -add_subdirectory(chotkeys) -add_subdirectory(cupdatecursor) -add_subdirectory(gmenuproxy) add_subdirectory(notificationd) add_subdirectory(sddm-helper) add_subdirectory(clipboard) diff --git a/README.md b/README.md index 99fba2b..8ecdeed 100644 --- a/README.md +++ b/README.md @@ -4,34 +4,18 @@ System backend and start session and more. ## Compile dependencies -```shell -sudo pacman -S extra-cmake-modules pkgconf qt5-base qt5-quickcontrols2 qt5-x11extras qt5-tools\ - kwindowsystem polkit polkit-qt5 xorg-server-devel xf86-input-libinput xf86-input-synaptics -``` - -For Ubuntu: -```shell -sudo apt install libpolkit-agent-1-dev libpolkit-qt5-1-dev libsm-dev libxtst-dev\ - libxcb-randr0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxcb-composite0-dev libxcb-damage0-dev libxcb-image0-dev libxcb-util0-dev libkf5idletime-dev -``` -(Yes it's annoying that so many xcb's packages here is needed to install. Isn't there a way to install one package and these `libxcb`s all get ready?) - -For Debian: -```shell -sudo apt install extra-cmake-modules pkg-config xserver-xorg-input-libinput-dev libx11-xcb-dev libxcb1-dev libxcb-randr0-dev\ - libxcb-keysyms1-dev libxcursor-dev libxcb-xfixes0-dev libxcb-damage0-dev libxcb-composite0-dev libxcb-shm0-dev libxcb-util-dev\ - libxcb-image0-dev libxcb-dpms0-dev libxcb-dri2-0-dev libxcb-dri3-dev libxcb-ewmh-dev libxcb-glx0-dev libxcb-record0-dev xserver-xorg-dev\ - xserver-xorg-input-synaptics-dev libxtst-dev libsm-dev libpolkit-qt5-1-dev libpolkit-agent-1-dev libkf5windowsystem-dev libkf5globalaccel-dev\ - libkf5coreaddons-dev libkf5idletime-dev libqt5x11extras5-dev qtbase5-dev qtdeclarative5-dev qtquickcontrols2-5-dev qttools5-dev qttools5-dev-tools -``` +Install Qt 6, KDE Frameworks 6, NetworkManager, Polkit, Fontconfig, FreeType +and the development tools provided by your distribution. The currently +retained settings daemon has its remaining input-backend dependencies +declared in `settings-daemon/CMakeLists.txt`. ## Runtime For the Wayland session, install KWin Wayland and select `Cutefish (KWin Wayland)` from the display manager. The session entry launches KWin with -XWayland enabled and starts `cutefish-session --wayland --no-wm` inside the -compositor. The Settings application and its X11-only settings daemon are not -started by this session yet. +Wayland enabled and starts `cutefish-session` inside the +compositor. The session starts the retained settings daemon, which in turn +starts the desktop components after its D-Bus service is ready. ## Build diff --git a/chotkeys/CMakeLists.txt b/chotkeys/CMakeLists.txt deleted file mode 100644 index 9693e7d..0000000 --- a/chotkeys/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -find_package(Qt6 COMPONENTS Core Widgets DBus Gui REQUIRED) -find_package(XCB MODULE REQUIRED COMPONENTS XCB KEYSYMS) -find_package(X11) - -set(PROJECT_SOURCES - main.cpp - application.cpp - hotkeys.cpp -) - -add_executable(chotkeys - ${PROJECT_SOURCES} -) - -target_link_libraries(chotkeys - PRIVATE - Qt6::Core - Qt6::Widgets - Qt6::DBus - Qt6::Gui - ${XCB_LIBS} - ${X11_LIBRARIES} - XCB::KEYSYMS -) - -install(TARGETS chotkeys RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/chotkeys/application.cpp b/chotkeys/application.cpp deleted file mode 100644 index afe049b..0000000 --- a/chotkeys/application.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2021 CutefishOS Team. - * - * Author: Reion Wong - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "application.h" -#include "hotkeys.h" - -#include -#include -#include -#include - -Application::Application(QObject *parent) - : QObject(parent) - , m_hotKeys(new Hotkeys) -{ - setupShortcuts(); - - connect(m_hotKeys, &Hotkeys::pressed, this, &Application::onPressed); - connect(m_hotKeys, &Hotkeys::released, this, &Application::onReleased); -} - -void Application::setupShortcuts() -{ - m_hotKeys->registerKey(QKeySequence(QKeyCombination(Qt::CTRL | Qt::ALT, Qt::Key_Delete))); - m_hotKeys->registerKey(QKeySequence(QKeyCombination(Qt::CTRL | Qt::ALT, Qt::Key_A))); - m_hotKeys->registerKey(QKeySequence(QKeyCombination(Qt::META, Qt::Key_L))); - //m_hotKeys->registerKey(QKeySequence(Qt::META + Qt::Key_6)); - m_hotKeys->registerKey(647); -} - -void Application::onPressed(QKeySequence keySeq) -{ - - if (keySeq.toString() == "Ctrl+Alt+Del") { - QProcess::startDetached("cutefish-shutdown", QStringList()); - } - - if (keySeq.toString() == "Meta+L") { - QProcess::startDetached("cutefish-screenlocker", QStringList()); - } - - if (keySeq.toString() == "Ctrl+Alt+A") { - QProcess::startDetached("cutefish-screenshot", QStringList()); - } - - if (keySeq.toString() == "Ʇ") { - // The launcher is a window of cutefish-shell, not a program to run. - QDBusInterface("com.cutefish.Launcher", "/Launcher", - "com.cutefish.Launcher", - QDBusConnection::sessionBus()).asyncCall("toggle"); - } -} - -void Application::onReleased(QKeySequence keySeq) -{ - Q_UNUSED(keySeq); -} diff --git a/chotkeys/application.h b/chotkeys/application.h deleted file mode 100644 index c81efe6..0000000 --- a/chotkeys/application.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2021 CutefishOS Team. - * - * Author: Reion Wong - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef APPLICATION_H -#define APPLICATION_H - -#include -#include "hotkeys.h" - -class Application : public QObject -{ - Q_OBJECT - -public: - explicit Application(QObject *parent = nullptr); - -private: - void setupShortcuts(); - -private slots: - void onPressed(QKeySequence keySeq); - void onReleased(QKeySequence keySeq); - -private: - Hotkeys *m_hotKeys; -}; - -#endif // APPLICATION_H diff --git a/chotkeys/hotkeys.cpp b/chotkeys/hotkeys.cpp deleted file mode 100644 index 6f3d2e2..0000000 --- a/chotkeys/hotkeys.cpp +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright (C) 2021 CutefishOS Team. - * - * Author: Reion Wong - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "hotkeys.h" -#include "x11utils.h" - -#include -#include -#include -#include - -// #include -// #include - -// XCB & X11 -#include -#include -#include - -#include - -Hotkeys::Hotkeys(QObject *parent) - : QObject(parent) -{ - qApp->installNativeEventFilter(this); -} - -Hotkeys::~Hotkeys() -{ - qApp->removeNativeEventFilter(this); -} - -bool Hotkeys::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) -{ - Q_UNUSED(result); - - if (eventType != "xcb_generic_event_t") { - return false; - } - - xcb_generic_event_t *e = static_cast(message); - - if (e->response_type == XCB_KEY_PRESS) { - xcb_key_press_event_t *keyEvent = static_cast(message); - quint32 keycode = keyEvent->detail; - quint32 mods = keyEvent->state; // & (ShiftMask | ControlMask | Mod1Mask | Mod3Mask); - quint32 id = keycode | mods; - -// int keyQt; -// KKeyServer::xcbKeyPressEventToQt(keyEvent, &keyQt); - -// bool found = false; -// for (QKeySequence &seq : m_shortcuts.values()) { -// if (seq == QKeySequence(keyQt)) { -// found = true; -// // emit pressed(seq); -// break; -// } -// } - -// if (!found && m_shortcuts.contains(id)) { -// // emit pressed(m_shortcuts[id]); -// } - -// // Keyboard needs to be ungrabed after XGrabKey() activates the grab, -// // otherwise it becomes frozen. -// xcb_void_cookie_t cookie = xcb_ungrab_keyboard_checked(c, XCB_TIME_CURRENT_TIME); -// xcb_flush(c); - -// // xcb_flush() only makes sure that the ungrab keyboard request has been -// // sent, but is not enough to make sure that request has been fulfilled. Use -// // xcb_request_check() to make sure that the request has been processed. -// xcb_request_check(c, cookie); - -// int keyQt; -// if (!KKeyServer::xcbKeyPressEventToQt(keyEvent, &keyQt)) { -// qDebug() << "KKeyServer::xcbKeyPressEventToQt failed"; -// return false; -// } - -// // All that work for this hey... argh... -// bool found = false; -// for (QKeySequence &seq : m_shortcuts.values()) { -// if (seq == QKeySequence(keyQt)) { -// found = true; -// emit pressed(seq); -// break; -// } -// } - - if (m_shortcuts.contains(id)) { - emit pressed(m_shortcuts[id]); - } - - return true; - - } else if (e->response_type == XCB_KEY_RELEASE) { - xcb_key_release_event_t *keyEvent = static_cast(message); - quint32 keycode = keyEvent->detail; - quint32 mods = keyEvent->state; // & (ShiftMask | ControlMask | Mod1Mask | Mod3Mask); - quint32 id = keycode | mods; - - // META - if (id == 197) { - id = 133; - } - - if (m_shortcuts.contains(id)) { - emit released(m_shortcuts[id]); - } - - return true; - } - - return false; -} - -void Hotkeys::registerKey(QKeySequence keySequence) -{ - if (keySequence.isEmpty()) - return; - - quint32 keycode = nativeKeycode(getKey(keySequence)); - quint32 mods = nativeModifiers(getMods(keySequence)); - quint32 keyId = keycode | mods; - - // META - if (keycode == 204 && mods == 0) { - keycode = 133; - keyId = keycode | mods; - } - - if (!m_shortcuts.contains(keyId)) { - registerKey(keycode, mods); - m_shortcuts.insert(keyId, keySequence); - } -} - -void Hotkeys::registerKey(quint32 keycode) -{ - if (!m_shortcuts.contains(keycode)) { - registerKey(keycode, 0); - m_shortcuts.insert(keycode, QKeySequence(keycode | 0)); - } -} - -void Hotkeys::registerKey(quint32 key, quint32 mods) -{ - xcb_grab_key(qGuiApp->nativeInterface()->connection(), - 1, - Cutefish::X11::rootWindow(), - mods, - key, - XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC); - - xcb_grab_key(qGuiApp->nativeInterface()->connection(), - 1, - Cutefish::X11::rootWindow(), - mods | XCB_MOD_MASK_2, - key, - XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC); -} - -void Hotkeys::unregisterKey(quint32 key, quint32 mods) -{ - xcb_ungrab_key(qGuiApp->nativeInterface()->connection(), key, Cutefish::X11::rootWindow(), mods); -} - -quint32 Hotkeys::nativeKeycode(Qt::Key k) -{ - /* keysymdef.h */ - quint32 key = 0; - if (k >= Qt::Key_F1 && k <= Qt::Key_F35) { - key = XK_F1 + (k - Qt::Key_F1); - } else if (k >= Qt::Key_Space && k <= Qt::Key_QuoteLeft) { - key = k; - } else if (k >= Qt::Key_BraceLeft && k <= Qt::Key_AsciiTilde) { - key = k; - } else if (k >= Qt::Key_nobreakspace && k <= Qt::Key_ydiaeresis) { - key = k; - } else { - switch (k) { - case Qt::Key_Escape: - key = XK_Escape; - break; - case Qt::Key_Tab: - case Qt::Key_Backtab: - key = XK_Tab; - break; - case Qt::Key_Backspace: - key = XK_BackSpace; - break; - case Qt::Key_Return: - case Qt::Key_Enter: - key = XK_Return; - break; - case Qt::Key_Insert: - key = XK_Insert; - break; - case Qt::Key_Delete: - key = XK_Delete; - break; - case Qt::Key_Pause: - key = XK_Pause; - break; - case Qt::Key_Print: - key = XK_Print; - break; - case Qt::Key_SysReq: - key = XK_Sys_Req; - break; - case Qt::Key_Clear: - key = XK_Clear; - break; - case Qt::Key_Home: - key = XK_Home; - break; - case Qt::Key_End: - key = XK_End; - break; - case Qt::Key_Left: - key = XK_Left; - break; - case Qt::Key_Up: - key = XK_Up; - break; - case Qt::Key_Right: - key = XK_Right; - break; - case Qt::Key_Down: - key = XK_Down; - break; - case Qt::Key_PageUp: - key = XK_Page_Up; - break; - case Qt::Key_PageDown: - key = XK_Page_Down; - break; - default: - key = 0; - } - } - return XKeysymToKeycode(qGuiApp->nativeInterface()->display(), key); -} - -quint32 Hotkeys::nativeModifiers(Qt::KeyboardModifiers m) -{ - quint32 mods = Qt::NoModifier; - - if (m & Qt::ShiftModifier) - mods |= ShiftMask; - if (m & Qt::ControlModifier) - mods |= ControlMask; - if (m & Qt::AltModifier) - mods |= Mod1Mask; - if (m & Qt::MetaModifier) - mods |= Mod4Mask; - - return mods; -} - -Qt::Key Hotkeys::getKey(const QKeySequence &keyseq) -{ - if (keyseq.isEmpty()) { - return Qt::Key(0); - } - - return Qt::Key(keyseq[0] & ~Qt::KeyboardModifierMask); -} - -Qt::KeyboardModifiers Hotkeys::getMods(const QKeySequence &keyseq) -{ - if (keyseq.isEmpty()) { - return Qt::KeyboardModifiers(); - } - - return Qt::KeyboardModifiers(keyseq[0] & Qt::KeyboardModifierMask); -} diff --git a/chotkeys/hotkeys.h b/chotkeys/hotkeys.h deleted file mode 100644 index 165d28e..0000000 --- a/chotkeys/hotkeys.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2021 CutefishOS Team. - * - * Author: Reion Wong - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef HOTKEYS_H -#define HOTKEYS_H - -#include -#include -#include -#include -#include -#include - -#include - -class Hotkeys : public QObject, public QAbstractNativeEventFilter -{ - Q_OBJECT - -public: - explicit Hotkeys(QObject *parent = nullptr); - ~Hotkeys(); - - bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override; - - void registerKey(QKeySequence keySequence); - void registerKey(quint32 keycode); - - void registerKey(quint32 key, quint32 mods); - void unregisterKey(quint32 key, quint32 mods); - - -signals: - void pressed(QKeySequence keySeq); - void released(QKeySequence keySeq); - -private: - quint32 nativeKeycode(Qt::Key k); - quint32 nativeModifiers(Qt::KeyboardModifiers m); - Qt::Key getKey(const QKeySequence& keyseq); - Qt::KeyboardModifiers getMods(const QKeySequence& keyseq); - -private: - QHash m_shortcuts; -}; - -#endif // HOTKEYS_H diff --git a/chotkeys/main.cpp b/chotkeys/main.cpp deleted file mode 100644 index 41b677e..0000000 --- a/chotkeys/main.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2021 CutefishOS Team. - * - * Author: Reion Wong - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include "application.h" - -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - a.setQuitOnLastWindowClosed(true); - - if (!QDBusConnection::sessionBus().registerService("com.cutefish.Chotkeys")) { - return -1; - } - - if (!QDBusConnection::sessionBus().registerObject("/Chotkeys", &a)) { - return -1; - } - - Application app; - return a.exec(); -} diff --git a/cmake/ECMFindModuleHelpers.cmake b/cmake/ECMFindModuleHelpers.cmake deleted file mode 100644 index f2e32f9..0000000 --- a/cmake/ECMFindModuleHelpers.cmake +++ /dev/null @@ -1,297 +0,0 @@ -#.rst: -# ECMFindModuleHelpers -# -------------------- -# -# Helper macros for find modules: ecm_find_package_version_check(), -# ecm_find_package_parse_components() and -# ecm_find_package_handle_library_components(). -# -# :: -# -# ecm_find_package_version_check() -# -# Prints warnings if the CMake version or the project's required CMake version -# is older than that required by extra-cmake-modules. -# -# :: -# -# ecm_find_package_parse_components( -# RESULT_VAR -# KNOWN_COMPONENTS [ [...]] -# [SKIP_DEPENDENCY_HANDLING]) -# -# This macro will populate with a list of components found in -# _FIND_COMPONENTS, after checking that all those components are in the -# list of KNOWN_COMPONENTS; if there are any unknown components, it will print -# an error or warning (depending on the value of _FIND_REQUIRED) and call -# return(). -# -# The order of components in is guaranteed to match the order they -# are listed in the KNOWN_COMPONENTS argument. -# -# If SKIP_DEPENDENCY_HANDLING is not set, for each component the variable -# __component_deps will be checked for dependent components. -# If is listed in _FIND_COMPONENTS, then all its (transitive) -# dependencies will also be added to . -# -# :: -# -# ecm_find_package_handle_library_components( -# COMPONENTS [ [...]] -# [SKIP_DEPENDENCY_HANDLING]) -# [SKIP_PKG_CONFIG]) -# -# Creates an imported library target for each component. The operation of this -# macro depends on the presence of a number of CMake variables. -# -# The __lib variable should contain the name of this library, -# and __header variable should contain the name of a header -# file associated with it (whatever relative path is normally passed to -# '#include'). __header_subdir variable can be used to specify -# which subdirectory of the include path the headers will be found in. -# ecm_find_package_components() will then search for the library -# and include directory (creating appropriate cache variables) and create an -# imported library target named ::. -# -# Additional variables can be used to provide additional information: -# -# If SKIP_PKG_CONFIG, the __pkg_config variable is set, and -# pkg-config is found, the pkg-config module given by -# __pkg_config will be searched for and used to help locate the -# library and header file. It will also be used to set -# __VERSION. -# -# Note that if version information is found via pkg-config, -# __FIND_VERSION can be set to require a particular version -# for each component. -# -# If SKIP_DEPENDENCY_HANDLING is not set, the INTERFACE_LINK_LIBRARIES property -# of the imported target for will be set to contain the imported -# targets for the components listed in __component_deps. -# _FOUND will also be set to false if any of the compoments in -# __component_deps are not found. This requires the components -# in __component_deps to be listed before in the -# COMPONENTS argument. -# -# The following variables will be set: -# -# ``_TARGETS`` -# the imported targets -# ``_LIBRARIES`` -# the found libraries -# ``_INCLUDE_DIRS`` -# the combined required include directories for the components -# ``_DEFINITIONS`` -# the "other" CFLAGS provided by pkg-config, if any -# ``_VERSION`` -# the value of ``__VERSION`` for the first component that -# has this variable set (note that components are searched for in the order -# they are passed to the macro), although if it is already set, it will not -# be altered -# -# Note that these variables are never cleared, so if -# ecm_find_package_handle_library_components() is called multiple times with -# different components (typically because of multiple find_package() calls) then -# ``_TARGETS``, for example, will contain all the targets found in any -# call (although no duplicates). -# -# Since pre-1.0.0. - -#============================================================================= -# Copyright 2014 Alex Merry -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. The name of the author may not be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -include(CMakeParseArguments) - -macro(ecm_find_package_version_check module_name) - if(CMAKE_VERSION VERSION_LESS 2.8.12) - message(FATAL_ERROR "CMake 2.8.12 is required by Find${module_name}.cmake") - endif() - if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12) - message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use Find${module_name}.cmake") - endif() -endmacro() - -macro(ecm_find_package_parse_components module_name) - set(ecm_fppc_options SKIP_DEPENDENCY_HANDLING) - set(ecm_fppc_oneValueArgs RESULT_VAR) - set(ecm_fppc_multiValueArgs KNOWN_COMPONENTS DEFAULT_COMPONENTS) - cmake_parse_arguments(ECM_FPPC "${ecm_fppc_options}" "${ecm_fppc_oneValueArgs}" "${ecm_fppc_multiValueArgs}" ${ARGN}) - - if(ECM_FPPC_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "Unexpected arguments to ecm_find_package_parse_components: ${ECM_FPPC_UNPARSED_ARGUMENTS}") - endif() - if(NOT ECM_FPPC_RESULT_VAR) - message(FATAL_ERROR "Missing RESULT_VAR argument to ecm_find_package_parse_components") - endif() - if(NOT ECM_FPPC_KNOWN_COMPONENTS) - message(FATAL_ERROR "Missing KNOWN_COMPONENTS argument to ecm_find_package_parse_components") - endif() - if(NOT ECM_FPPC_DEFAULT_COMPONENTS) - set(ECM_FPPC_DEFAULT_COMPONENTS ${ECM_FPPC_KNOWN_COMPONENTS}) - endif() - - if(${module_name}_FIND_COMPONENTS) - set(ecm_fppc_requestedComps ${${module_name}_FIND_COMPONENTS}) - - if(NOT ECM_FPPC_SKIP_DEPENDENCY_HANDLING) - # Make sure deps are included - foreach(ecm_fppc_comp ${ecm_fppc_requestedComps}) - foreach(ecm_fppc_dep_comp ${${module_name}_${ecm_fppc_comp}_component_deps}) - list(FIND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}" ecm_fppc_index) - if("${ecm_fppc_index}" STREQUAL "-1") - if(NOT ${module_name}_FIND_QUIETLY) - message(STATUS "${module_name}: ${ecm_fppc_comp} requires ${${module_name}_${ecm_fppc_comp}_component_deps}") - endif() - list(APPEND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}") - endif() - endforeach() - endforeach() - else() - message(STATUS "Skipping dependency handling for ${module_name}") - endif() - list(REMOVE_DUPLICATES ecm_fppc_requestedComps) - - # This makes sure components are listed in the same order as - # KNOWN_COMPONENTS (potentially important for inter-dependencies) - set(${ECM_FPPC_RESULT_VAR}) - foreach(ecm_fppc_comp ${ECM_FPPC_KNOWN_COMPONENTS}) - list(FIND ecm_fppc_requestedComps "${ecm_fppc_comp}" ecm_fppc_index) - if(NOT "${ecm_fppc_index}" STREQUAL "-1") - list(APPEND ${ECM_FPPC_RESULT_VAR} "${ecm_fppc_comp}") - list(REMOVE_AT ecm_fppc_requestedComps ${ecm_fppc_index}) - endif() - endforeach() - # if there are any left, they are unknown components - if(ecm_fppc_requestedComps) - set(ecm_fppc_msgType STATUS) - if(${module_name}_FIND_REQUIRED) - set(ecm_fppc_msgType FATAL_ERROR) - endif() - if(NOT ${module_name}_FIND_QUIETLY) - message(${ecm_fppc_msgType} "${module_name}: requested unknown components ${ecm_fppc_requestedComps}") - endif() - return() - endif() - else() - set(${ECM_FPPC_RESULT_VAR} ${ECM_FPPC_DEFAULT_COMPONENTS}) - endif() -endmacro() - -macro(ecm_find_package_handle_library_components module_name) - set(ecm_fpwc_options SKIP_PKG_CONFIG SKIP_DEPENDENCY_HANDLING) - set(ecm_fpwc_oneValueArgs) - set(ecm_fpwc_multiValueArgs COMPONENTS) - cmake_parse_arguments(ECM_FPWC "${ecm_fpwc_options}" "${ecm_fpwc_oneValueArgs}" "${ecm_fpwc_multiValueArgs}" ${ARGN}) - - if(ECM_FPWC_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "Unexpected arguments to ecm_find_package_handle_components: ${ECM_FPWC_UNPARSED_ARGUMENTS}") - endif() - if(NOT ECM_FPWC_COMPONENTS) - message(FATAL_ERROR "Missing COMPONENTS argument to ecm_find_package_handle_components") - endif() - - include(FindPackageHandleStandardArgs) - find_package(PkgConfig) - foreach(ecm_fpwc_comp ${ECM_FPWC_COMPONENTS}) - set(ecm_fpwc_dep_vars) - set(ecm_fpwc_dep_targets) - if(NOT SKIP_DEPENDENCY_HANDLING) - foreach(ecm_fpwc_dep ${${module_name}_${ecm_fpwc_comp}_component_deps}) - list(APPEND ecm_fpwc_dep_vars "${module_name}_${ecm_fpwc_dep}_FOUND") - list(APPEND ecm_fpwc_dep_targets "${module_name}::${ecm_fpwc_dep}") - endforeach() - endif() - - if(NOT ECM_FPWC_SKIP_PKG_CONFIG AND ${module_name}_${ecm_fpwc_comp}_pkg_config) - pkg_check_modules(PKG_${module_name}_${ecm_fpwc_comp} QUIET - ${${module_name}_${ecm_fpwc_comp}_pkg_config}) - endif() - - find_path(${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR - NAMES ${${module_name}_${ecm_fpwc_comp}_header} - HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_INCLUDE_DIRS} - PATH_SUFFIXES ${${module_name}_${ecm_fpwc_comp}_header_subdir} - ) - find_library(${module_name}_${ecm_fpwc_comp}_LIBRARY - NAMES ${${module_name}_${ecm_fpwc_comp}_lib} - HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_LIBRARY_DIRS} - ) - - set(${module_name}_${ecm_fpwc_comp}_VERSION "${PKG_${module_name}_${ecm_fpwc_comp}_VERSION}") - if(NOT ${module_name}_VERSION) - set(${module_name}_VERSION ${${module_name}_${ecm_fpwc_comp}_VERSION}) - endif() - - find_package_handle_standard_args(${module_name}_${ecm_fpwc_comp} - FOUND_VAR - ${module_name}_${ecm_fpwc_comp}_FOUND - REQUIRED_VARS - ${module_name}_${ecm_fpwc_comp}_LIBRARY - ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR - ${ecm_fpwc_dep_vars} - VERSION_VAR - ${module_name}_${ecm_fpwc_comp}_VERSION - ) - - mark_as_advanced( - ${module_name}_${ecm_fpwc_comp}_LIBRARY - ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR - ) - - if(${module_name}_${ecm_fpwc_comp}_FOUND) - list(APPEND ${module_name}_LIBRARIES - "${${module_name}_${ecm_fpwc_comp}_LIBRARY}") - list(APPEND ${module_name}_INCLUDE_DIRS - "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}") - set(${module_name}_DEFINITIONS - ${${module_name}_DEFINITIONS} - ${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}) - if(NOT TARGET ${module_name}::${ecm_fpwc_comp}) - add_library(${module_name}::${ecm_fpwc_comp} UNKNOWN IMPORTED) - set_target_properties(${module_name}::${ecm_fpwc_comp} PROPERTIES - IMPORTED_LOCATION "${${module_name}_${ecm_fpwc_comp}_LIBRARY}" - INTERFACE_COMPILE_OPTIONS "${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}" - INTERFACE_INCLUDE_DIRECTORIES "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}" - INTERFACE_LINK_LIBRARIES "${ecm_fpwc_dep_targets}" - ) - endif() - list(APPEND ${module_name}_TARGETS - "${module_name}::${ecm_fpwc_comp}") - endif() - endforeach() - if(${module_name}_LIBRARIES) - list(REMOVE_DUPLICATES ${module_name}_LIBRARIES) - endif() - if(${module_name}_INCLUDE_DIRS) - list(REMOVE_DUPLICATES ${module_name}_INCLUDE_DIRS) - endif() - if(${module_name}_DEFINITIONS) - list(REMOVE_DUPLICATES ${module_name}_DEFINITIONS) - endif() - if(${module_name}_TARGETS) - list(REMOVE_DUPLICATES ${module_name}_TARGETS) - endif() -endmacro() diff --git a/cmake/FindX11_XCB.cmake b/cmake/FindX11_XCB.cmake deleted file mode 100644 index d1382eb..0000000 --- a/cmake/FindX11_XCB.cmake +++ /dev/null @@ -1,92 +0,0 @@ -# SPDX-FileCopyrightText: 2014 Alex Merry -# SPDX-FileCopyrightText: 2011 Fredrik Höglund -# SPDX-FileCopyrightText: 2008 Helio Chissini de Castro -# SPDX-FileCopyrightText: 2007 Matthias Kretz -# -# SPDX-License-Identifier: BSD-3-Clause - -#[=======================================================================[.rst: -FindX11_XCB ------------ - -Try to find the X11 XCB compatibility library. - -This will define the following variables: - -``X11_XCB_FOUND`` - True if (the requested version of) libX11-xcb is available -``X11_XCB_VERSION`` - The version of libX11-xcb (this is not guaranteed to be set even when - X11_XCB_FOUND is true) -``X11_XCB_LIBRARIES`` - This can be passed to target_link_libraries() instead of the ``EGL::EGL`` - target -``X11_XCB_INCLUDE_DIR`` - This should be passed to target_include_directories() if the target is not - used for linking -``X11_XCB_DEFINITIONS`` - This should be passed to target_compile_options() if the target is not - used for linking - -If ``X11_XCB_FOUND`` is TRUE, it will also define the following imported -target: - -``X11::XCB`` - The X11 XCB compatibility library - -In general we recommend using the imported target, as it is easier to use. -Bear in mind, however, that if the target is in the link interface of an -exported library, it must be made available by the package config file. - -Since pre-1.0.0. -#]=======================================================================] - -# use pkg-config to get the directories and then use these values -# in the FIND_PATH() and FIND_LIBRARY() calls -find_package(PkgConfig QUIET) -pkg_check_modules(PKG_X11_XCB QUIET x11-xcb) - -set(X11_XCB_DEFINITIONS ${PKG_X11_XCB_CFLAGS_OTHER}) -set(X11_XCB_VERSION ${PKG_X11_XCB_VERSION}) - -find_path(X11_XCB_INCLUDE_DIR - NAMES X11/Xlib-xcb.h - HINTS ${PKG_X11_XCB_INCLUDE_DIRS} -) -find_library(X11_XCB_LIBRARY - NAMES X11-xcb - HINTS ${PKG_X11_XCB_LIBRARY_DIRS} -) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(X11_XCB - FOUND_VAR - X11_XCB_FOUND - REQUIRED_VARS - X11_XCB_LIBRARY - X11_XCB_INCLUDE_DIR - VERSION_VAR - X11_XCB_VERSION -) - -if(X11_XCB_FOUND AND NOT TARGET X11::XCB) - add_library(X11::XCB UNKNOWN IMPORTED) - set_target_properties(X11::XCB PROPERTIES - IMPORTED_LOCATION "${X11_XCB_LIBRARY}" - INTERFACE_COMPILE_OPTIONS "${X11_XCB_DEFINITIONS}" - INTERFACE_INCLUDE_DIRECTORIES "${X11_XCB_INCLUDE_DIR}" - ) -endif() - -mark_as_advanced(X11_XCB_INCLUDE_DIR X11_XCB_LIBRARY) - -# compatibility variables -set(X11_XCB_LIBRARIES ${X11_XCB_LIBRARY}) -set(X11_XCB_INCLUDE_DIRS ${X11_XCB_INCLUDE_DIR}) -set(X11_XCB_VERSION_STRING ${X11_XCB_VERSION}) - -include(FeatureSummary) -set_package_properties(X11_XCB PROPERTIES - URL "https://xorg.freedesktop.org/" - DESCRIPTION "A compatibility library for code that translates Xlib API calls into XCB calls" -) diff --git a/cmake/FindXCB.cmake b/cmake/FindXCB.cmake deleted file mode 100644 index 192c0be..0000000 --- a/cmake/FindXCB.cmake +++ /dev/null @@ -1,177 +0,0 @@ -# SPDX-FileCopyrightText: 2011 Fredrik Höglund -# SPDX-FileCopyrightText: 2013 Martin Gräßlin -# SPDX-FileCopyrightText: 2014-2015 Alex Merry -# -# SPDX-License-Identifier: BSD-3-Clause - -#[=======================================================================[.rst: -FindXCB -------- - -Try to find XCB. - -This is a component-based find module, which makes use of the COMPONENTS and -OPTIONAL_COMPONENTS arguments to find_module. The following components are -available:: - - XCB - ATOM AUX COMPOSITE CURSOR DAMAGE - DPMS DRI2 DRI3 EVENT EWMH - GLX ICCCM IMAGE KEYSYMS PRESENT - RANDR RECORD RENDER RENDERUTIL RES - SCREENSAVER SHAPE SHM SYNC UTIL - XEVIE XF86DRI XFIXES XINERAMA XINPUT - XKB XPRINT XTEST XV XVMC - -If no components are specified, this module will act as though all components -except XINPUT (which is considered unstable) were passed to -OPTIONAL_COMPONENTS. - -This module will define the following variables, independently of the -components searched for or found: - -``XCB_FOUND`` - True if (the requestion version of) xcb is available -``XCB_VERSION`` - Found xcb version -``XCB_TARGETS`` - A list of all targets imported by this module (note that there may be more - than the components that were requested) -``XCB_LIBRARIES`` - This can be passed to target_link_libraries() instead of the imported - targets -``XCB_INCLUDE_DIRS`` - This should be passed to target_include_directories() if the targets are - not used for linking -``XCB_DEFINITIONS`` - This should be passed to target_compile_options() if the targets are not - used for linking - -For each searched-for components, ``XCB__FOUND`` will be set to -true if the corresponding xcb library was found, and false otherwise. If -``XCB__FOUND`` is true, the imported target ``XCB::`` -will be defined. This module will also attempt to determine -``XCB_*_VERSION`` variables for each imported target, although -``XCB_VERSION`` should normally be sufficient. - -In general we recommend using the imported targets, as they are easier to use -and provide more control. Bear in mind, however, that if any target is in the -link interface of an exported library, it must be made available by the -package config file. - -Since pre-1.0.0. -#]=======================================================================] - -include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpers.cmake) - -# Note that this list needs to be ordered such that any component -# appears after its dependencies -set(XCB_known_components - XCB - RENDER - SHAPE - XFIXES - SHM - ATOM - AUX - COMPOSITE - CURSOR - DAMAGE - DPMS - DRI2 - DRI3 - EVENT - EWMH - GLX - ICCCM - IMAGE - KEYSYMS - PRESENT - RANDR - RECORD - RENDERUTIL - RES - SCREENSAVER - SYNC - UTIL - XEVIE - XF86DRI - XINERAMA - XINPUT - XKB - XPRINT - XTEST - XV - XVMC -) - -# XINPUT is unstable; do not include it by default -set(XCB_default_components ${XCB_known_components}) -list(REMOVE_ITEM XCB_default_components "XINPUT") - -# default component info: xcb components have fairly predictable -# header files, library names and pkg-config names -foreach(_comp ${XCB_known_components}) - string(TOLOWER "${_comp}" _lc_comp) - set(XCB_${_comp}_component_deps XCB) - set(XCB_${_comp}_pkg_config "xcb-${_lc_comp}") - set(XCB_${_comp}_lib "xcb-${_lc_comp}") - set(XCB_${_comp}_header "xcb/${_lc_comp}.h") -endforeach() -# exceptions -set(XCB_XCB_component_deps) -set(XCB_COMPOSITE_component_deps XCB XFIXES) -set(XCB_DAMAGE_component_deps XCB XFIXES) -set(XCB_IMAGE_component_deps XCB SHM) -set(XCB_RENDERUTIL_component_deps XCB RENDER) -set(XCB_XFIXES_component_deps XCB RENDER SHAPE) -set(XCB_XVMC_component_deps XCB XV) -set(XCB_XV_component_deps XCB SHM) -set(XCB_XCB_pkg_config "xcb") -set(XCB_XCB_lib "xcb") -set(XCB_ATOM_header "xcb/xcb_atom.h") -set(XCB_ATOM_lib "xcb-util") -set(XCB_AUX_header "xcb/xcb_aux.h") -set(XCB_AUX_lib "xcb-util") -set(XCB_CURSOR_header "xcb/xcb_cursor.h") -set(XCB_EVENT_header "xcb/xcb_event.h") -set(XCB_EVENT_lib "xcb-util") -set(XCB_EWMH_header "xcb/xcb_ewmh.h") -set(XCB_ICCCM_header "xcb/xcb_icccm.h") -set(XCB_IMAGE_header "xcb/xcb_image.h") -set(XCB_KEYSYMS_header "xcb/xcb_keysyms.h") -set(XCB_PIXEL_header "xcb/xcb_pixel.h") -set(XCB_RENDERUTIL_header "xcb/xcb_renderutil.h") -set(XCB_RENDERUTIL_lib "xcb-render-util") -set(XCB_UTIL_header "xcb/xcb_util.h") - -ecm_find_package_parse_components(XCB - RESULT_VAR XCB_components - KNOWN_COMPONENTS ${XCB_known_components} - DEFAULT_COMPONENTS ${XCB_default_components} -) - -list(FIND XCB_components "XINPUT" _XCB_XINPUT_index) -if (NOT _XCB_XINPUT_index EQUAL -1) - message(AUTHOR_WARNING "XINPUT from XCB was requested: this is EXPERIMENTAL and is likely to unavailable on many systems!") -endif() - -ecm_find_package_handle_library_components(XCB - COMPONENTS ${XCB_components} -) - -find_package_handle_standard_args(XCB - FOUND_VAR - XCB_FOUND - REQUIRED_VARS - XCB_LIBRARIES - VERSION_VAR - XCB_VERSION - HANDLE_COMPONENTS -) - -include(FeatureSummary) -set_package_properties(XCB PROPERTIES - URL "https://xcb.freedesktop.org/" - DESCRIPTION "X protocol C-language Binding" -) diff --git a/cupdatecursor/CMakeLists.txt b/cupdatecursor/CMakeLists.txt deleted file mode 100644 index 45e0555..0000000 --- a/cupdatecursor/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -find_package(Qt6 COMPONENTS Core Gui REQUIRED) -find_package(X11) - -add_executable(cupdatecursor - main.cpp -) -target_link_libraries(cupdatecursor - Qt6::Core - Qt6::Gui - ${X11_LIBRARIES} - X11::X11 - X11::Xi - X11::Xcursor -) - -install(TARGETS cupdatecursor DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/cupdatecursor/main.cpp b/cupdatecursor/main.cpp deleted file mode 100644 index 1762b0e..0000000 --- a/cupdatecursor/main.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -#include -#include - -inline void applyTheme(const QString &theme, int size) -{ - Display *display = qGuiApp->nativeInterface()->display(); - - if (!theme.isEmpty()) - XcursorSetTheme(display, QFile::encodeName(theme)); - - if (size > 0) - XcursorSetDefaultSize(display, size); - - Cursor handle = XcursorLibraryLoadCursor(display, "left_ptr"); - XDefineCursor(display, DefaultRootWindow(display), handle); - XFreeCursor(display, handle); - XFlush(display); - - // For KWin - QSettings settings(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/kcminputrc", - QSettings::IniFormat); - settings.beginGroup("Mouse"); - settings.setValue("cursorTheme", theme); - settings.setValue("cursorSize", size); - settings.endGroup(); - settings.sync(); -} - -int main(int argc, char *argv[]) -{ - QGuiApplication::setDesktopSettingsAware(false); - QGuiApplication a(argc, argv); - - if (argc != 3) - return 1; - - if (!qGuiApp->nativeInterface()) - return 2; - - QString theme = QFile::decodeName(argv[1]); - QString size = QFile::decodeName(argv[2]); - - applyTheme(theme, size.toInt()); - - return 0; -} diff --git a/debian/control b/debian/control index 826f6d8..e5784dd 100644 --- a/debian/control +++ b/debian/control @@ -6,32 +6,8 @@ Build-Depends: cmake, debhelper (>= 9), extra-cmake-modules, pkg-config, - xserver-xorg-input-libinput-dev, - libx11-xcb-dev, - libxcb1-dev, - libxcb-randr0-dev, - libxcb-keysyms1-dev, - libxcursor-dev, - libxcb-xfixes0-dev, - libxcb-damage0-dev, - libxcb-composite0-dev, - libxcb-shm0-dev, - libxcb-util-dev, - libxcb-image0-dev, - libxcb-dpms0-dev, - libxcb-dri2-0-dev, - libxcb-dri3-dev, - libxcb-ewmh-dev, - libxcb-glx0-dev, - libxcb-record0-dev, - xserver-xorg-dev, - xserver-xorg-input-synaptics-dev, - libxtst-dev, - libsm-dev, libpolkit-qt6-1-dev, libpolkit-agent-1-dev, - libkf6windowsystem-dev, - libkf6globalaccel-dev, libkf6coreaddons-dev, libkf6idletime-dev, qt6-base-dev, diff --git a/gmenuproxy/CMakeLists.txt b/gmenuproxy/CMakeLists.txt deleted file mode 100644 index 052ed3d..0000000 --- a/gmenuproxy/CMakeLists.txt +++ /dev/null @@ -1,53 +0,0 @@ -find_package(AppMenuGtkModule) -find_package(KF6WindowSystem) -find_package(KF6CoreAddons) -set_package_properties(AppMenuGtkModule PROPERTIES TYPE RUNTIME) - -add_definitions(-DQT_NO_CAST_TO_ASCII --DQT_NO_CAST_FROM_ASCII --DQT_NO_CAST_FROM_BYTEARRAY) - -find_package(XCB - REQUIRED COMPONENTS - XCB -) - -set(GMENU_DBUSMENU_PROXY_SRCS - extend/dbusmenutypes_p.cpp -# extend/dbusmenushortcut_p.cpp - - main.cpp - menuproxy.cpp - window.cpp - menu.cpp - actions.cpp - dbusmenuadaptor.cpp - gdbusmenutypes_p.cpp - icons.cpp - utils.cpp - ) - -# qt_add_dbus_adaptor(GMENU_DBUSMENU_PROXY_SRCS ./com.canonical.dbusmenu.xml window.h Window) - -add_executable(cutefish-gmenuproxy ${GMENU_DBUSMENU_PROXY_SRCS}) - -set_package_properties(XCB PROPERTIES TYPE REQUIRED) - -target_link_libraries(cutefish-gmenuproxy - Qt6::Core - Qt6::Gui - Qt6::DBus - Qt6::Widgets - KF6::CoreAddons - KF6::WindowSystem - XCB::XCB -) - -configure_file( - cutefish-gmenuproxy.service.in - cutefish-gmenuproxy.service - @ONLY -) - -install(TARGETS cutefish-gmenuproxy DESTINATION ${CMAKE_INSTALL_BINDIR}) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cutefish-gmenuproxy.service DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/systemd/user/) diff --git a/gmenuproxy/actions.cpp b/gmenuproxy/actions.cpp deleted file mode 100644 index e831d2a..0000000 --- a/gmenuproxy/actions.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Kai Uwe Broulik - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#include "actions.h" - -#include -#include -#include -#include -#include -#include -#include - -static const QString s_orgGtkActions = QStringLiteral("org.gtk.Actions"); - -Actions::Actions(const QString &serviceName, const QString &objectPath, QObject *parent) - : QObject(parent) - , m_serviceName(serviceName) - , m_objectPath(objectPath) -{ - Q_ASSERT(!serviceName.isEmpty()); - Q_ASSERT(!m_objectPath.isEmpty()); - - if (!QDBusConnection::sessionBus().connect(serviceName, - objectPath, - s_orgGtkActions, - QStringLiteral("Changed"), - this, - SLOT(onActionsChanged(QStringList, StringBoolMap, QVariantMap, GMenuActionMap)))) { - qDebug() << "Failed to subscribe to action changes for" << parent << "on" << serviceName << "at" << objectPath; - } -} - -Actions::~Actions() = default; - -void Actions::load() -{ - QDBusMessage msg = QDBusMessage::createMethodCall(m_serviceName, m_objectPath, s_orgGtkActions, QStringLiteral("DescribeAll")); - - QDBusPendingReply reply = QDBusConnection::sessionBus().asyncCall(msg); - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); - connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { - QDBusPendingReply reply = *watcher; - if (reply.isError()) { - qDebug() << "Failed to get actions from" << m_serviceName << "at" << m_objectPath << reply.error(); - emit failedToLoad(); - } else { - m_actions = reply.value(); - emit loaded(); - } - watcher->deleteLater(); - }); -} - -bool Actions::get(const QString &name, GMenuAction &action) const -{ - auto it = m_actions.find(name); - if (it == m_actions.constEnd()) { - return false; - } - - action = *it; - return true; -} - -GMenuActionMap Actions::getAll() const -{ - return m_actions; -} - -void Actions::trigger(const QString &name, const QVariant &target, uint timestamp) -{ - if (!m_actions.contains(name)) { - qDebug() << "Cannot invoke action" << name << "which doesn't exist"; - return; - } - - QDBusMessage msg = QDBusMessage::createMethodCall(m_serviceName, m_objectPath, s_orgGtkActions, QStringLiteral("Activate")); - msg << name; - - QVariantList args; - if (target.isValid()) { - args << target; - } - msg << QVariant::fromValue(args); - - QVariantMap platformData; - - if (timestamp) { - // From documentation: - // If the startup notification id is not available, this can be just "_TIMEtime", where - // time is the time stamp from the event triggering the call. - // see also gtkwindow.c extract_time_from_startup_id and startup_id_is_fake - platformData.insert(QStringLiteral("desktop-startup-id"), QStringLiteral("_TIME") + QString::number(timestamp)); - } - - msg << platformData; - - QDBusPendingReply reply = QDBusConnection::sessionBus().asyncCall(msg); - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); - connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, name](QDBusPendingCallWatcher *watcher) { - QDBusPendingReply reply = *watcher; - if (reply.isError()) { - qDebug() << "Failed to invoke action" << name << "on" << m_serviceName << "at" << m_objectPath << reply.error(); - } - watcher->deleteLater(); - }); -} - -bool Actions::isValid() const -{ - return !m_actions.isEmpty(); -} - -void Actions::onActionsChanged(const QStringList &removed, const StringBoolMap &enabledChanges, const QVariantMap &stateChanges, const GMenuActionMap &added) -{ - // Collect the actions that we removed, altered, or added, so we can eventually signal changes for all menus that contain one of those actions - QStringList dirtyActions; - - // TODO I bet for most of the loops below we could use a nice short std algorithm - - for (const QString &removedAction : removed) { - if (m_actions.remove(removedAction)) { - dirtyActions.append(removedAction); - } - } - - for (auto it = enabledChanges.constBegin(), end = enabledChanges.constEnd(); it != end; ++it) { - const QString &actionName = it.key(); - const bool enabled = it.value(); - - auto actionIt = m_actions.find(actionName); - if (actionIt == m_actions.end()) { - qDebug() << "Got enabled changed for action" << actionName << "which we don't know"; - continue; - } - - GMenuAction &action = *actionIt; - if (action.enabled != enabled) { - action.enabled = enabled; - dirtyActions.append(actionName); - } else { - qDebug() << "Got enabled change for action" << actionName << "which didn't change it"; - } - } - - for (auto it = stateChanges.constBegin(), end = stateChanges.constEnd(); it != end; ++it) { - const QString &actionName = it.key(); - const QVariant &state = it.value(); - - auto actionIt = m_actions.find(actionName); - if (actionIt == m_actions.end()) { - qDebug() << "Got state changed for action" << actionName << "which we don't know"; - continue; - } - - GMenuAction &action = *actionIt; - - if (action.state.isEmpty()) { - qDebug() << "Got new state for action" << actionName << "that didn't have any state before"; - action.state.append(state); - dirtyActions.append(actionName); - } else { - // Action state is a list but the state change only sends us a single variant, so just overwrite the first one - QVariant &firstState = action.state.first(); - if (firstState != state) { - firstState = state; - dirtyActions.append(actionName); - } else { - qDebug() << "Got state change for action" << actionName << "which didn't change it"; - } - } - } - - // unite() will result in keys being present multiple times, do it manually and overwrite existing ones - for (auto it = added.constBegin(), end = added.constEnd(); it != end; ++it) { - const QString &actionName = it.key(); - - // if ((DBUSMENUPROXY).isInfoEnabled()) { - // if (m_actions.contains(actionName)) { - // qDebug() << "Got new action" << actionName << "that we already have, overwriting existing one"; - // } - // } - - m_actions.insert(actionName, it.value()); - - dirtyActions.append(actionName); - } - - if (!dirtyActions.isEmpty()) { - emit actionsChanged(dirtyActions); - } -} diff --git a/gmenuproxy/actions.h b/gmenuproxy/actions.h deleted file mode 100644 index a558e65..0000000 --- a/gmenuproxy/actions.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Kai Uwe Broulik - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#pragma once - -#include -#include -#include - -#include "gdbusmenutypes_p.h" - -class Actions : public QObject -{ - Q_OBJECT - -public: - Actions(const QString &serviceName, const QString &objectPath, QObject *parent = nullptr); - ~Actions() override; - - void load(); - - bool get(const QString &name, GMenuAction &action) const; - GMenuActionMap getAll() const; - void trigger(const QString &name, const QVariant &target, uint timestamp = 0); - - bool isValid() const; // basically "has actions" - -Q_SIGNALS: - void loaded(); - void failedToLoad(); // expose error? - void actionsChanged(const QStringList &dirtyActions); - -private slots: - void onActionsChanged(const QStringList &removed, const StringBoolMap &enabledChanges, const QVariantMap &stateChanges, const GMenuActionMap &added); - -private: - GMenuActionMap m_actions; - - QString m_serviceName; - QString m_objectPath; -}; diff --git a/gmenuproxy/com.canonical.dbusmenu.xml b/gmenuproxy/com.canonical.dbusmenu.xml deleted file mode 100644 index c90776a..0000000 --- a/gmenuproxy/com.canonical.dbusmenu.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gmenuproxy/cutefish-gmenuproxy.service.in b/gmenuproxy/cutefish-gmenuproxy.service.in deleted file mode 100644 index ad095b1..0000000 --- a/gmenuproxy/cutefish-gmenuproxy.service.in +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=Proxies GTK DBus menus to a Cutefish readable format -PartOf=graphical-session.target - -[Service] -ExecStart=@CMAKE_INSTALL_FULL_BINDIR@/cutefish-gmenuproxy -Restart=on-failure -Type=simple -Slice=background.slice -TimeoutSec=5sec diff --git a/gmenuproxy/dbusmenuadaptor.cpp b/gmenuproxy/dbusmenuadaptor.cpp deleted file mode 100644 index d870bd0..0000000 --- a/gmenuproxy/dbusmenuadaptor.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * This file was generated by qdbusxml2cpp version 0.8 - * Command line was: qdbusxml2cpp -m -a dbusmenuadaptor -i window.h -l Window /home/reion/Cutefish/core/gmenuproxy/com.canonical.dbusmenu.xml - * - * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. - * - * This is an auto-generated file. - * Do not edit! All changes made to it will be lost. - */ - -#include "dbusmenuadaptor.h" -#include -#include -#include -#include -#include -#include -#include - -/* - * Implementation of adaptor class DbusmenuAdaptor - */ - -DbusmenuAdaptor::DbusmenuAdaptor(Window *parent) - : QDBusAbstractAdaptor(parent) -{ - // constructor - setAutoRelaySignals(true); -} - -DbusmenuAdaptor::~DbusmenuAdaptor() -{ - // destructor -} - -QString DbusmenuAdaptor::status() const -{ - // get the value of property Status - return qvariant_cast< QString >(parent()->property("Status")); -} - -uint DbusmenuAdaptor::version() const -{ - // get the value of property Version - return qvariant_cast< uint >(parent()->property("Version")); -} - -bool DbusmenuAdaptor::AboutToShow(int id) -{ - // handle method call com.canonical.dbusmenu.AboutToShow - return parent()->AboutToShow(id); -} - -void DbusmenuAdaptor::Event(int id, const QString &eventId, const QDBusVariant &data, uint timestamp) -{ - // handle method call com.canonical.dbusmenu.Event - parent()->Event(id, eventId, data, timestamp); -} - -DBusMenuItemList DbusmenuAdaptor::GetGroupProperties(const QList &ids, const QStringList &propertyNames) -{ - // handle method call com.canonical.dbusmenu.GetGroupProperties - return parent()->GetGroupProperties(ids, propertyNames); -} - -uint DbusmenuAdaptor::GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, DBusMenuLayoutItem &item) -{ - // handle method call com.canonical.dbusmenu.GetLayout - return parent()->GetLayout(parentId, recursionDepth, propertyNames, item); -} - -QDBusVariant DbusmenuAdaptor::GetProperty(int id, const QString &property) -{ - // handle method call com.canonical.dbusmenu.GetProperty - return parent()->GetProperty(id, property); -} - - -#include "dbusmenuadaptor.moc" diff --git a/gmenuproxy/dbusmenuadaptor.h b/gmenuproxy/dbusmenuadaptor.h deleted file mode 100644 index 60e2e93..0000000 --- a/gmenuproxy/dbusmenuadaptor.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file was generated by qdbusxml2cpp version 0.8 - * Command line was: qdbusxml2cpp -m -a dbusmenuadaptor -i window.h -l Window /home/reion/Cutefish/core/gmenuproxy/com.canonical.dbusmenu.xml - * - * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. - * - * This is an auto-generated file. - * This file may have been hand-edited. Look for HAND-EDIT comments - * before re-generating it. - */ - -#ifndef DBUSMENUADAPTOR_H -#define DBUSMENUADAPTOR_H - -#include -#include -#include -#include "window.h" -QT_BEGIN_NAMESPACE -class QByteArray; -template class QList; -template class QMap; -class QString; -class QVariant; -QT_END_NAMESPACE - -/* - * Adaptor class for interface com.canonical.dbusmenu - */ -class DbusmenuAdaptor: public QDBusAbstractAdaptor -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "com.canonical.dbusmenu") - Q_CLASSINFO("D-Bus Introspection", "" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" - "") -public: - DbusmenuAdaptor(Window *parent); - virtual ~DbusmenuAdaptor(); - - inline Window *parent() const - { return static_cast(QObject::parent()); } - -public: // PROPERTIES - Q_PROPERTY(QString Status READ status) - QString status() const; - - Q_PROPERTY(uint Version READ version) - uint version() const; - -public Q_SLOTS: // METHODS - bool AboutToShow(int id); - Q_NOREPLY void Event(int id, const QString &eventId, const QDBusVariant &data, uint timestamp); - DBusMenuItemList GetGroupProperties(const QList &ids, const QStringList &propertyNames); - uint GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, DBusMenuLayoutItem &item); - QDBusVariant GetProperty(int id, const QString &property); -Q_SIGNALS: // SIGNALS - void ItemActivationRequested(int id, uint timeStamp); - void ItemsPropertiesUpdated(DBusMenuItemList in0, DBusMenuItemKeysList in1); - void LayoutUpdated(uint revision, int parentId); -}; - -#endif diff --git a/gmenuproxy/extend/dbusmenushortcut_p.cpp b/gmenuproxy/extend/dbusmenushortcut_p.cpp deleted file mode 100644 index 0257f2b..0000000 --- a/gmenuproxy/extend/dbusmenushortcut_p.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* This file is part of the dbusmenu-qt library - SPDX-FileCopyrightText: 2009 Canonical - SPDX-FileContributor: Aurelien Gateau - - SPDX-License-Identifier: LGPL-2.0-or-later -*/ -#include "dbusmenushortcut_p.h" - -// Qt -#include - -static const int QT_COLUMN = 0; -static const int DM_COLUMN = 1; - -static void processKeyTokens(QStringList *tokens, int srcCol, int dstCol) -{ - struct Row { - const char *zero; - const char *one; - const char *operator[](int col) const - { - return col == 0 ? zero : one; - } - }; - static const Row table[] = {{"Meta", "Super"}, - {"Ctrl", "Control"}, - // Special cases for compatibility with libdbusmenu-glib which uses - // "plus" for "+" and "minus" for "-". - // cf https://bugs.launchpad.net/libdbusmenu-qt/+bug/712565 - {"+", "plus"}, - {"-", "minus"}, - {nullptr, nullptr}}; - - const Row *ptr = table; - for (; ptr->zero != nullptr; ++ptr) { - const char *from = (*ptr)[srcCol]; - const char *to = (*ptr)[dstCol]; - tokens->replaceInStrings(from, to); - } -} - -DBusMenuShortcut DBusMenuShortcut::fromKeySequence(const QKeySequence &sequence) -{ - QString string = sequence.toString(); - DBusMenuShortcut shortcut; - QStringList tokens = string.split(QStringLiteral(", ")); - Q_FOREACH (QString token, tokens) { - // Hack: Qt::CTRL | Qt::Key_Plus is turned into the string "Ctrl++", - // but we don't want the call to token.split() to consider the - // second '+' as a separator so we replace it with its final value. - token.replace(QLatin1String("++"), QLatin1String("+plus")); - QStringList keyTokens = token.split('+'); - processKeyTokens(&keyTokens, QT_COLUMN, DM_COLUMN); - shortcut << keyTokens; - } - return shortcut; -} - -QKeySequence DBusMenuShortcut::toKeySequence() const -{ - QStringList tmp; - Q_FOREACH (const QStringList &keyTokens_, *this) { - QStringList keyTokens = keyTokens_; - processKeyTokens(&keyTokens, DM_COLUMN, QT_COLUMN); - tmp << keyTokens.join(QLatin1String("+")); - } - QString string = tmp.join(QLatin1String(", ")); - return QKeySequence::fromString(string); -} diff --git a/gmenuproxy/extend/dbusmenushortcut_p.h b/gmenuproxy/extend/dbusmenushortcut_p.h deleted file mode 100644 index 1d5d7a2..0000000 --- a/gmenuproxy/extend/dbusmenushortcut_p.h +++ /dev/null @@ -1,22 +0,0 @@ -/* This file is part of the dbusmenu-qt library - SPDX-FileCopyrightText: 2009 Canonical - SPDX-FileContributor: Aurelien Gateau - - SPDX-License-Identifier: LGPL-2.0-or-later -*/ -#pragma once - -// Qt -#include -#include - -class QKeySequence; - -class DBusMenuShortcut : public QList -{ -public: - QKeySequence toKeySequence() const; - static DBusMenuShortcut fromKeySequence(const QKeySequence &); -}; - -Q_DECLARE_METATYPE(DBusMenuShortcut) diff --git a/gmenuproxy/extend/dbusmenutypes_p.cpp b/gmenuproxy/extend/dbusmenutypes_p.cpp deleted file mode 100644 index b0125fb..0000000 --- a/gmenuproxy/extend/dbusmenutypes_p.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* This file is part of the dbusmenu-qt library - SPDX-FileCopyrightText: 2009 Canonical - SPDX-FileContributor: Aurelien Gateau - - SPDX-License-Identifier: LGPL-2.0-or-later -*/ -#include "dbusmenutypes_p.h" - -// Local -#include "dbusmenushortcut_p.h" - -// Qt -#include -#include - -//// DBusMenuItem -QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuItem &obj) -{ - argument.beginStructure(); - argument << obj.id << obj.properties; - argument.endStructure(); - return argument; -} - -const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuItem &obj) -{ - argument.beginStructure(); - argument >> obj.id >> obj.properties; - argument.endStructure(); - return argument; -} - -//// DBusMenuItemKeys -QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuItemKeys &obj) -{ - argument.beginStructure(); - argument << obj.id << obj.properties; - argument.endStructure(); - return argument; -} - -const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuItemKeys &obj) -{ - argument.beginStructure(); - argument >> obj.id >> obj.properties; - argument.endStructure(); - return argument; -} - -//// DBusMenuLayoutItem -QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuLayoutItem &obj) -{ - argument.beginStructure(); - argument << obj.id << obj.properties; - argument.beginArray(qMetaTypeId()); - Q_FOREACH (const DBusMenuLayoutItem &child, obj.children) { - argument << QDBusVariant(QVariant::fromValue(child)); - } - argument.endArray(); - argument.endStructure(); - return argument; -} - -const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuLayoutItem &obj) -{ - argument.beginStructure(); - argument >> obj.id >> obj.properties; - argument.beginArray(); - while (!argument.atEnd()) { - QDBusVariant dbusVariant; - argument >> dbusVariant; - QDBusArgument childArgument = dbusVariant.variant().value(); - - DBusMenuLayoutItem child; - childArgument >> child; - obj.children.append(child); - } - argument.endArray(); - argument.endStructure(); - return argument; -} - -//// DBusMenuShortcut -QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuShortcut &obj) -{ - argument.beginArray(qMetaTypeId()); - typename QList::ConstIterator it = obj.constBegin(); - typename QList::ConstIterator end = obj.constEnd(); - for (; it != end; ++it) - argument << *it; - argument.endArray(); - return argument; -} - -const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuShortcut &obj) -{ - argument.beginArray(); - obj.clear(); - while (!argument.atEnd()) { - QStringList item; - argument >> item; - obj.push_back(item); - } - argument.endArray(); - return argument; -} - -void DBusMenuTypes_register() -{ - static bool registered = false; - if (registered) { - return; - } - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - registered = true; -} diff --git a/gmenuproxy/extend/dbusmenutypes_p.h b/gmenuproxy/extend/dbusmenutypes_p.h deleted file mode 100644 index f6dc79f..0000000 --- a/gmenuproxy/extend/dbusmenutypes_p.h +++ /dev/null @@ -1,80 +0,0 @@ -/* This file is part of the dbusmenu-qt library - SPDX-FileCopyrightText: 2009 Canonical - SPDX-FileContributor: Aurelien Gateau - - SPDX-License-Identifier: LGPL-2.0-or-later -*/ -#pragma once - -// Qt -#include -#include -#include - -class QDBusArgument; - -//// DBusMenuItem -/** - * Internal struct used to communicate on DBus - */ -struct DBusMenuItem { - int id; - QVariantMap properties; -}; - -Q_DECLARE_METATYPE(DBusMenuItem) - -QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuItem &item); -const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuItem &item); - -typedef QList DBusMenuItemList; - -Q_DECLARE_METATYPE(DBusMenuItemList) - -//// DBusMenuItemKeys -/** - * Represents a list of keys for a menu item - */ -struct DBusMenuItemKeys { - int id; - QStringList properties; -}; - -Q_DECLARE_METATYPE(DBusMenuItemKeys) - -QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuItemKeys &); -const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuItemKeys &); - -typedef QList DBusMenuItemKeysList; - -Q_DECLARE_METATYPE(DBusMenuItemKeysList) - -//// DBusMenuLayoutItem -/** - * Represents an item with its children. GetLayout() returns a - * DBusMenuLayoutItemList. - */ -struct DBusMenuLayoutItem; -struct DBusMenuLayoutItem { - int id; - QVariantMap properties; - QList children; -}; - -Q_DECLARE_METATYPE(DBusMenuLayoutItem) - -QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuLayoutItem &); -const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuLayoutItem &); - -typedef QList DBusMenuLayoutItemList; - -Q_DECLARE_METATYPE(DBusMenuLayoutItemList) - -//// DBusMenuShortcut - -class DBusMenuShortcut; - -QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuShortcut &); -const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuShortcut &); - -void DBusMenuTypes_register(); \ No newline at end of file diff --git a/gmenuproxy/gdbusmenutypes_p.cpp b/gmenuproxy/gdbusmenutypes_p.cpp deleted file mode 100644 index 10f248c..0000000 --- a/gmenuproxy/gdbusmenutypes_p.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Kai Uwe Broulik - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#include "gdbusmenutypes_p.h" - -#include -#include - -// GMenuItem -QDBusArgument &operator<<(QDBusArgument &argument, const GMenuItem &item) -{ - argument.beginStructure(); - argument << item.id << item.section << item.items; - argument.endStructure(); - return argument; -} - -const QDBusArgument &operator>>(const QDBusArgument &argument, GMenuItem &item) -{ - argument.beginStructure(); - argument >> item.id >> item.section >> item.items; - argument.endStructure(); - return argument; -} - -// GMenuSection -QDBusArgument &operator<<(QDBusArgument &argument, const GMenuSection &item) -{ - argument.beginStructure(); - argument << item.subscription << item.menu; - argument.endStructure(); - return argument; -} - -const QDBusArgument &operator>>(const QDBusArgument &argument, GMenuSection &item) -{ - argument.beginStructure(); - argument >> item.subscription >> item.menu; - argument.endStructure(); - return argument; -} - -// GMenuChange -QDBusArgument &operator<<(QDBusArgument &argument, const GMenuChange &item) -{ - argument.beginStructure(); - argument << item.subscription << item.menu << item.changePosition << item.itemsToRemoveCount << item.itemsToInsert; - argument.endStructure(); - return argument; -} - -const QDBusArgument &operator>>(const QDBusArgument &argument, GMenuChange &item) -{ - argument.beginStructure(); - argument >> item.subscription >> item.menu >> item.changePosition >> item.itemsToRemoveCount >> item.itemsToInsert; - argument.endStructure(); - return argument; -} - -// GMenuActionProperty -QDBusArgument &operator<<(QDBusArgument &argument, const GMenuAction &item) -{ - argument.beginStructure(); - argument << item.enabled << item.signature << item.state; - argument.endStructure(); - return argument; -} - -const QDBusArgument &operator>>(const QDBusArgument &argument, GMenuAction &item) -{ - argument.beginStructure(); - argument >> item.enabled >> item.signature >> item.state; - argument.endStructure(); - return argument; -} - -// GMenuActionsChange -QDBusArgument &operator<<(QDBusArgument &argument, const GMenuActionsChange &item) -{ - argument.beginStructure(); - argument << item.removed << item.enabledChanged << item.stateChanged << item.added; - argument.endStructure(); - return argument; -} - -const QDBusArgument &operator>>(const QDBusArgument &argument, GMenuActionsChange &item) -{ - argument.beginStructure(); - argument >> item.removed >> item.enabledChanged >> item.stateChanged >> item.added; - argument.endStructure(); - return argument; -} - -void GDBusMenuTypes_register() -{ - static bool registered = false; - if (registered) { - return; - } - - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - - qDBusRegisterMetaType(); - - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - - registered = true; -} diff --git a/gmenuproxy/gdbusmenutypes_p.h b/gmenuproxy/gdbusmenutypes_p.h deleted file mode 100644 index e8c1333..0000000 --- a/gmenuproxy/gdbusmenutypes_p.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Kai Uwe Broulik - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#pragma once - -#include -#include -#include -#include - -class QDBusArgument; - -// Various -using VariantMapList = QList; -Q_DECLARE_METATYPE(VariantMapList); - -using StringBoolMap = QMap; -Q_DECLARE_METATYPE(StringBoolMap); - -// Menu item itself (Start method) -struct GMenuItem { - uint id; - uint section; - VariantMapList items; -}; -Q_DECLARE_METATYPE(GMenuItem); - -QDBusArgument &operator<<(QDBusArgument &argument, const GMenuItem &item); -const QDBusArgument &operator>>(const QDBusArgument &argument, GMenuItem &item); - -using GMenuItemList = QList; -Q_DECLARE_METATYPE(GMenuItemList); - -// Information about what section or submenu to use for a particular entry -struct GMenuSection { - uint subscription; - uint menu; -}; -Q_DECLARE_METATYPE(GMenuSection); - -QDBusArgument &operator<<(QDBusArgument &argument, const GMenuSection &item); -const QDBusArgument &operator>>(const QDBusArgument &argument, GMenuSection &item); - -// Changes of a menu item (Changed signal) -struct GMenuChange { - uint subscription; - uint menu; - - uint changePosition; - uint itemsToRemoveCount; - VariantMapList itemsToInsert; -}; -Q_DECLARE_METATYPE(GMenuChange); - -QDBusArgument &operator<<(QDBusArgument &argument, const GMenuChange &item); -const QDBusArgument &operator>>(const QDBusArgument &argument, GMenuChange &item); - -using GMenuChangeList = QList; -Q_DECLARE_METATYPE(GMenuChangeList); - -// An application action -struct GMenuAction { - bool enabled; - QDBusSignature signature; - QVariantList state; -}; -Q_DECLARE_METATYPE(GMenuAction); - -QDBusArgument &operator<<(QDBusArgument &argument, const GMenuAction &item); -const QDBusArgument &operator>>(const QDBusArgument &argument, GMenuAction &item); - -using GMenuActionMap = QMap; -Q_DECLARE_METATYPE(GMenuActionMap); - -struct GMenuActionsChange { - QStringList removed; - QMap enabledChanged; - QVariantMap stateChanged; - GMenuActionMap added; -}; -Q_DECLARE_METATYPE(GMenuActionsChange); - -QDBusArgument &operator<<(QDBusArgument &argument, const GMenuActionsChange &item); -const QDBusArgument &operator>>(const QDBusArgument &argument, GMenuActionsChange &item); - -void GDBusMenuTypes_register(); diff --git a/gmenuproxy/gmenudbusmenuproxy.desktop b/gmenuproxy/gmenudbusmenuproxy.desktop deleted file mode 100644 index ab65a32..0000000 --- a/gmenuproxy/gmenudbusmenuproxy.desktop +++ /dev/null @@ -1,50 +0,0 @@ -[Desktop Entry] -Exec=gmenudbusmenuproxy -Name=GMenuDBusMenuProxy -Name[ar]=وكيل قائمة D-Bus لـ GMenu. -Name[ast]=GMenuDBusMenuProxy -Name[az]=GMenuDBusMenuProxy -Name[ca]=GMenuDBusMenuProxy -Name[ca@valencia]=GMenuDBusMenuProxy -Name[da]=GMenuDBusMenuProxy -Name[de]=GMenuDBusMenuProxy -Name[el]=GMenuDBusMenuProxy -Name[en_GB]=GMenuDBusMenuProxy -Name[es]=GMenuDBusMenuProxy -Name[et]=GMenuDBusMenuProxy -Name[eu]=GMenuDBusMenuProxy -Name[fi]=GMenuDBusMenuProxy -Name[fr]=GMenuDBusMenuProxy -Name[gl]=Proxy de menú por D-Bus para GMenu. -Name[hi]=जीमेन्यूडीबसमेन्यूप्रॉक्सी -Name[hu]=GMenuDBusMenuProxy -Name[ia]=GMenuDBusMenuProxy -Name[id]=GMenuDBusMenuProxy -Name[it]=GMenuDBusMenuProxy -Name[ko]=GMenuDBusMenuProxy -Name[lt]=GMenuDBusMenuProxy -Name[ml]=ജിമെനുഡിബസ്‍മെനുപ്രോക്സി -Name[nl]=GMenuDBusMenuProxy -Name[nn]=GMenuDBusMenuProxy -Name[pa]=GMenuDBusMenuProxy -Name[pl]=GMenuDBusMenuProxy -Name[pt]=GMenuDBusMenuProxy -Name[pt_BR]=GMenuDBusMenuProxy -Name[ro]=GMenuDBusMenuProxy -Name[ru]=GMenuDBusMenuProxy -Name[sk]=GMenuDBusMenuProxy -Name[sl]=GMenuDBusMenuProxy -Name[sv]=GMenuDBusMenuProxy -Name[ta]=GMenuDBusMenuProxy -Name[tr]=GMenuDBusMenuProxy -Name[uk]=Проксі-меню GMenu D-Bus -Name[vi]=GMenuDBusMenuProxy -Name[x-test]=xxGMenuDBusMenuProxyxx -Name[zh_CN]=GMenuDBusMenuProxy -Name[zh_TW]=GMenuDBusMenuProxy -Type=Application -X-KDE-StartupNotify=false -NoDisplay=true -OnlyShowIn=KDE; -X-KDE-autostart-phase=1 -X-systemd-skip=true diff --git a/gmenuproxy/icons.cpp b/gmenuproxy/icons.cpp deleted file mode 100644 index 3cca6c3..0000000 --- a/gmenuproxy/icons.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Kai Uwe Broulik - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#include "icons.h" - -#include -#include - -QString Icons::actionIcon(const QString &actionName) -{ - QString icon; - - QString action = actionName; - - if (action.isEmpty()) { - return icon; - } - - static const QHash s_icons{ - {QStringLiteral("new"), QStringLiteral("document-new")}, // appmenu-gtk-module "New" - {QStringLiteral("image-new"), QStringLiteral("document-new")}, // Gimp "New" item - {QStringLiteral("adddirect"), QStringLiteral("document-new")}, // LibreOffice "New" item - {QStringLiteral("filenew"), QStringLiteral("document-new")}, // Pluma "New" item - {QStringLiteral("new-window"), QStringLiteral("window-new")}, - {QStringLiteral("newwindow"), QStringLiteral("window-new")}, - {QStringLiteral("yelp-window-new"), QStringLiteral("window-new")}, // Gnome help - {QStringLiteral("new-tab"), QStringLiteral("tab-new")}, - {QStringLiteral("open"), QStringLiteral("document-open")}, - {QStringLiteral("open-location"), QStringLiteral("document-open-remote")}, - {QStringLiteral("openremote"), QStringLiteral("document-open-remote")}, - {QStringLiteral("save"), QStringLiteral("document-save")}, - {QStringLiteral("save-as"), QStringLiteral("document-save-as")}, - {QStringLiteral("saveas"), QStringLiteral("document-save-as")}, - {QStringLiteral("save-all"), QStringLiteral("document-save-all")}, - {QStringLiteral("saveall"), QStringLiteral("document-save-all")}, - {QStringLiteral("import"), QStringLiteral("document-import")}, - {QStringLiteral("export"), QStringLiteral("document-export")}, - {QStringLiteral("exportto"), QStringLiteral("document-export")}, // LibreOffice - {QStringLiteral("exporttopdf"), QStringLiteral("viewpdf")}, // LibreOffice, the icon it uses but the name is quite random - {QStringLiteral("webhtml"), QStringLiteral("text-html")}, // LibreOffice - {QStringLiteral("printpreview"), QStringLiteral("document-print-preview")}, - {QStringLiteral("print-preview"), QStringLiteral("document-print-preview")}, - {QStringLiteral("print"), QStringLiteral("document-print")}, - {QStringLiteral("print-gtk"), QStringLiteral("document-print")}, // Gimp - {QStringLiteral("mail-image"), QStringLiteral("mail-message-new")}, // Gimp - {QStringLiteral("sendmail"), QStringLiteral("mail-message-new")}, // LibreOffice - {QStringLiteral("sendviabluetooth"), QStringLiteral("preferences-system-bluetooth")}, // LibreOffice - {QStringLiteral("sendviabluetooth"), QStringLiteral("preferences-system-bluetooth")}, // LibreOffice - {QStringLiteral("document-properties"), QStringLiteral("document-properties")}, - {QStringLiteral("close"), QStringLiteral("document-close")}, // appmenu-gtk-module "Close" - {QStringLiteral("closedoc"), QStringLiteral("document-close")}, - {QStringLiteral("close-all"), QStringLiteral("document-close")}, - {QStringLiteral("closeall"), QStringLiteral("document-close")}, - {QStringLiteral("closewin"), QStringLiteral("window-close")}, // LibreOffice - {QStringLiteral("quit"), QStringLiteral("application-exit")}, - - {QStringLiteral("undo"), QStringLiteral("edit-undo")}, - {QStringLiteral("redo"), QStringLiteral("edit-redo")}, - {QStringLiteral("revert"), QStringLiteral("document-revert")}, - {QStringLiteral("cut"), QStringLiteral("edit-cut")}, - {QStringLiteral("copy"), QStringLiteral("edit-copy")}, - {QStringLiteral("paste"), QStringLiteral("edit-paste")}, - {QStringLiteral("duplicate"), QStringLiteral("edit-duplicate")}, - - {QStringLiteral("preferences"), QStringLiteral("settings-configure")}, - {QStringLiteral("optionstreedialog"), QStringLiteral("settings-configure")}, // LibreOffice - {QStringLiteral("keyboard-shortcuts"), QStringLiteral("configure-shortcuts")}, - - {QStringLiteral("fullscreen"), QStringLiteral("view-fullscreen")}, - - {QStringLiteral("find"), QStringLiteral("edit-find")}, - {QStringLiteral("searchfind"), QStringLiteral("edit-find")}, - {QStringLiteral("replace"), QStringLiteral("edit-find-replace")}, - {QStringLiteral("searchreplace"), QStringLiteral("edit-find-replace")}, // LibreOffice - {QStringLiteral("searchdialog"), QStringLiteral("edit-find-replace")}, // LibreOffice - {QStringLiteral("find-replace"), QStringLiteral("edit-find-replace")}, // Inkscape - {QStringLiteral("select-all"), QStringLiteral("edit-select-all")}, - {QStringLiteral("selectall"), QStringLiteral("edit-select-all")}, - {QStringLiteral("select-none"), QStringLiteral("edit-select-invert")}, - {QStringLiteral("select-invert"), QStringLiteral("edit-select-invert")}, - {QStringLiteral("invert-selection"), QStringLiteral("edit-select-invert")}, // Inkscape - {QStringLiteral("check-spelling"), QStringLiteral("tools-check-spelling")}, - {QStringLiteral("set-language"), QStringLiteral("set-language")}, - - {QStringLiteral("increasesize"), QStringLiteral("zoom-in")}, - {QStringLiteral("decreasesize"), QStringLiteral("zoom-out")}, - {QStringLiteral("zoom-in"), QStringLiteral("zoom-in")}, - {QStringLiteral("zoom-out"), QStringLiteral("zoom-out")}, - {QStringLiteral("zoomfit"), QStringLiteral("zoom-fit-best")}, - {QStringLiteral("zoom-fit-in"), QStringLiteral("zoom-fit-best")}, - {QStringLiteral("show-guides"), QStringLiteral("show-guides")}, - {QStringLiteral("show-grid"), QStringLiteral("show-grid")}, - - {QStringLiteral("rotateclockwise"), QStringLiteral("object-rotate-right")}, - {QStringLiteral("rotatecounterclockwise"), QStringLiteral("object-rotate-left")}, - {QStringLiteral("fliphorizontally"), QStringLiteral("object-flip-horizontal")}, - {QStringLiteral("image-flip-horizontal"), QStringLiteral("object-flip-horizontal")}, - {QStringLiteral("flipvertically"), QStringLiteral("object-flip-vertical")}, - {QStringLiteral("image-flip-vertical"), QStringLiteral("object-flip-vertical")}, - {QStringLiteral("image-scale"), QStringLiteral("transform-scale")}, - - {QStringLiteral("bold"), QStringLiteral("format-text-bold")}, - {QStringLiteral("italic"), QStringLiteral("format-text-italic")}, - {QStringLiteral("underline"), QStringLiteral("format-text-underline")}, - {QStringLiteral("strikeout"), QStringLiteral("format-text-strikethrough")}, - {QStringLiteral("superscript"), QStringLiteral("format-text-superscript")}, - {QStringLiteral("subscript"), QStringLiteral("format-text-subscript")}, - // "grow" is a bit unspecific to always set it to "grow font", so use the exact ID here - {QStringLiteral(".uno:Grow"), QStringLiteral("format-font-size-more")}, // LibreOffice - {QStringLiteral(".uno:Shrink"), QStringLiteral("format-font-size-less")}, // LibreOffice - // also a bit unspecific? - {QStringLiteral("alignleft"), QStringLiteral("format-justify-left")}, - {QStringLiteral("alignhorizontalcenter"), QStringLiteral("format-justify-center")}, - {QStringLiteral("alignright"), QStringLiteral("format-justify-right")}, - {QStringLiteral("alignjustified"), QStringLiteral("format-justify-fill")}, - {QStringLiteral("incrementindent"), QStringLiteral("format-indent-more")}, - {QStringLiteral("decrementindent"), QStringLiteral("format-indent-less")}, - {QStringLiteral("defaultbullet"), QStringLiteral("format-list-unordered")}, // LibreOffice - {QStringLiteral("defaultnumbering"), QStringLiteral("format-list-ordered")}, // LibreOffice - - {QStringLiteral("sortascending"), QStringLiteral("view-sort-ascending")}, - {QStringLiteral("sortdescending"), QStringLiteral("view-sort-descending")}, - - {QStringLiteral("autopilotmenu"), QStringLiteral("tools-wizard")}, // LibreOffice - - {QStringLiteral("layers-new"), QStringLiteral("layer-new")}, - {QStringLiteral("layers-duplicate"), QStringLiteral("layer-duplicate")}, - {QStringLiteral("layers-delete"), QStringLiteral("layer-delete")}, - {QStringLiteral("layers-anchor"), QStringLiteral("anchor")}, - - {QStringLiteral("slideshow"), QStringLiteral("media-playback-start")}, // Gwenview uses this icon for that - {QStringLiteral("playvideo"), QStringLiteral("media-playback-start")}, - - {QStringLiteral("addtags"), QStringLiteral("tag-new")}, - {QStringLiteral("newevent"), QStringLiteral("appointment-new")}, - - {QStringLiteral("previous-document"), QStringLiteral("go-previous")}, - {QStringLiteral("prevphoto"), QStringLiteral("go-previous")}, - {QStringLiteral("next-document"), QStringLiteral("go-next")}, - {QStringLiteral("nextphoto"), QStringLiteral("go-next")}, - - {QStringLiteral("redeye"), QStringLiteral("redeyes")}, - {QStringLiteral("crop"), QStringLiteral("transform-crop")}, - {QStringLiteral("move"), QStringLiteral("transform-move")}, - {QStringLiteral("rotate"), QStringLiteral("transform-rotate")}, - {QStringLiteral("scale"), QStringLiteral("transform-scale")}, - {QStringLiteral("shear"), QStringLiteral("transform-shear")}, - {QStringLiteral("flip"), QStringLiteral("object-flip-horizontal")}, - {QStringLiteral("flag"), QStringLiteral("flag-red")}, // is there a "mark" or "important" icon that isn't email? - - {QStringLiteral("tools-measure"), QStringLiteral("measure")}, - {QStringLiteral("tools-text"), QStringLiteral("draw-text")}, - {QStringLiteral("tools-color-picker"), QStringLiteral("color-picker")}, - {QStringLiteral("tools-paintbrush"), QStringLiteral("draw-brush")}, - {QStringLiteral("tools-eraser"), QStringLiteral("draw-eraser")}, - {QStringLiteral("tools-paintbrush"), QStringLiteral("draw-brush")}, - - {QStringLiteral("help"), QStringLiteral("help-contents")}, - {QStringLiteral("helpindex"), QStringLiteral("help-contents")}, - {QStringLiteral("contents"), QStringLiteral("help-contents")}, - {QStringLiteral("helpcontents"), QStringLiteral("help-contents")}, - {QStringLiteral("context-help"), QStringLiteral("help-whatsthis")}, - {QStringLiteral("extendedhelp"), QStringLiteral("help-whatsthis")}, // LibreOffice - {QStringLiteral("helpreportproblem"), QStringLiteral("tools-report-bug")}, - {QStringLiteral("sendfeedback"), QStringLiteral("tools-report-bug")}, // LibreOffice - {QStringLiteral("about"), QStringLiteral("help-about")}, - - {QStringLiteral("emptytrash"), QStringLiteral("trash-empty")}, - {QStringLiteral("movetotrash"), QStringLiteral("user-trash-symbolic")}, - - // Gnome help - {QStringLiteral("yelp-application-larger-text"), QStringLiteral("format-font-size-more")}, - {QStringLiteral("yelp-application-smaller-text"), QStringLiteral("format-font-size-less")}, // LibreOffice - - // LibreOffice documents in its New menu - {QStringLiteral("private:factory/swriter"), QStringLiteral("application-vnd.oasis.opendocument.text")}, - {QStringLiteral("private:factory/scalc"), QStringLiteral("application-vnd.oasis.opendocument.spreadsheet")}, - {QStringLiteral("private:factory/simpress"), QStringLiteral("application-vnd.oasis.opendocument.presentation")}, - {QStringLiteral("private:factory/sdraw"), QStringLiteral("application-vnd.oasis.opendocument.graphics")}, - {QStringLiteral("private:factory/swriter/web"), QStringLiteral("text-html")}, - {QStringLiteral("private:factory/smath"), QStringLiteral("application-vnd.oasis.opendocument.formula")}, - }; - - // Sometimes we get additional arguments (?slot=123) we don't care about - const int questionMarkIndex = action.indexOf(QLatin1Char('?')); - if (questionMarkIndex > -1) { - action.truncate(questionMarkIndex); - } - - icon = s_icons.value(action); - - if (icon.isEmpty()) { - const int dotIndex = action.indexOf(QLatin1Char('.')); // app., win., or unity. prefix - - QString prefix; - if (dotIndex > -1) { - prefix = action.left(dotIndex); - - action = action.mid(dotIndex + 1); - } - - // appmenu-gtk-module - if (prefix == QLatin1String("unity")) { - // Remove superfluous hyphens added by appmenu-gtk-module - // First remove multiple subsequent ones - static QRegularExpression subsequentHyphenRegExp(QStringLiteral("-{2,}")); - action.replace(subsequentHyphenRegExp, QStringLiteral("-")); - - // now we can be sure we only have a single hyphen at the start or end, remove it if needed - if (action.startsWith(QLatin1Char('-'))) { - action.remove(0, 1); - } - if (action.endsWith(QLatin1Char('-'))) { - action.chop(1); - } - - // It also turns accelerators (&) into hyphens, so remove any hyphen that comes before - // a lower-case letter ("mid sentence"), e.g. "P-references" - static QRegularExpression strayHyphenRegExp(QStringLiteral("-(?=[a-z]+)")); - action.remove(strayHyphenRegExp); - } - - icon = s_icons.value(action); - } - - if (icon.isEmpty()) { - static const auto s_dup1Prefix = QStringLiteral("dup:1:"); // can it be dup2 also? - if (action.startsWith(s_dup1Prefix)) { - action = action.mid(s_dup1Prefix.length()); - } - - static const auto s_unoPrefix = QStringLiteral(".uno:"); // LibreOffice with appmenu-gtk - if (action.startsWith(s_unoPrefix)) { - action = action.mid(s_unoPrefix.length()); - } - - // LibreOffice's "Open" entry is always "OpenFromAppname" so we just chop that off - if (action.startsWith(QLatin1String("OpenFrom"))) { - action.truncate(4); // basically "Open" - } - - icon = s_icons.value(action); - } - - if (icon.isEmpty()) { - static const auto s_commonPrefix = QStringLiteral("Common"); - if (action.startsWith(s_commonPrefix)) { - action = action.mid(s_commonPrefix.length()); - } - - icon = s_icons.value(action); - } - - if (icon.isEmpty()) { - static const auto s_prefixes = QStringList{ - // Gimp with appmenu-gtk - QStringLiteral("file-"), - QStringLiteral("edit-"), - QStringLiteral("view-"), - QStringLiteral("image-"), - QStringLiteral("layers-"), - QStringLiteral("colors-"), - QStringLiteral("tools-"), - QStringLiteral("plug-in-"), - QStringLiteral("windows-"), - QStringLiteral("dialogs-"), - QStringLiteral("help-"), - }; - - for (const QString &prefix : s_prefixes) { - if (action.startsWith(prefix)) { - action = action.mid(prefix.length()); - break; - } - } - - icon = s_icons.value(action); - } - - if (icon.isEmpty()) { - action = action.toLower(); - icon = s_icons.value(action); - } - - if (icon.isEmpty()) { - static const auto s_prefixes = QStringList{ - // Pluma with appmenu-gtk - QStringLiteral("file"), - QStringLiteral("edit"), - QStringLiteral("view"), - QStringLiteral("help"), - }; - - for (const QString &prefix : s_prefixes) { - if (action.startsWith(prefix)) { - action = action.mid(prefix.length()); - break; - } - } - - icon = s_icons.value(action); - } - - return icon; -} diff --git a/gmenuproxy/icons.h b/gmenuproxy/icons.h deleted file mode 100644 index 46dd1db..0000000 --- a/gmenuproxy/icons.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Kai Uwe Broulik - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#pragma once - -#include - -namespace Icons -{ -QString actionIcon(const QString &actionName); - -} diff --git a/gmenuproxy/main.cpp b/gmenuproxy/main.cpp deleted file mode 100644 index 72e510c..0000000 --- a/gmenuproxy/main.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Kai Uwe Broulik - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#include -#include - -#include - -#include "menuproxy.h" - -int main(int argc, char **argv) -{ - qputenv("QT_QPA_PLATFORM", "xcb"); - - QGuiApplication::setDesktopSettingsAware(false); - - QGuiApplication app(argc, argv); - - if (!KWindowSystem::isPlatformX11()) { - qFatal("qdbusmenuproxy is only useful XCB. Aborting"); - } - - auto disableSessionManagement = [](QSessionManager &sm) { - sm.setRestartHint(QSessionManager::RestartNever); - }; - QObject::connect(&app, &QGuiApplication::commitDataRequest, disableSessionManagement); - QObject::connect(&app, &QGuiApplication::saveStateRequest, disableSessionManagement); - - app.setQuitOnLastWindowClosed(false); - - MenuProxy proxy; - - return app.exec(); -} diff --git a/gmenuproxy/menu.cpp b/gmenuproxy/menu.cpp deleted file mode 100644 index 044a1c1..0000000 --- a/gmenuproxy/menu.cpp +++ /dev/null @@ -1,328 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Kai Uwe Broulik - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#include "menu.h" - -#include -#include -#include -#include -#include -#include - -#include - -#include "utils.h" - -static const QString s_orgGtkMenus = QStringLiteral("org.gtk.Menus"); - -Menu::Menu(const QString &serviceName, const QString &objectPath, QObject *parent) - : QObject(parent) - , m_serviceName(serviceName) - , m_objectPath(objectPath) -{ - Q_ASSERT(!serviceName.isEmpty()); - Q_ASSERT(!m_objectPath.isEmpty()); - - if (!QDBusConnection::sessionBus() - .connect(m_serviceName, m_objectPath, s_orgGtkMenus, QStringLiteral("Changed"), this, SLOT(onMenuChanged(GMenuChangeList)))) { - qDebug() << "Failed to subscribe to menu changes for" << parent << "on" << serviceName << "at" << objectPath; - } -} - -Menu::~Menu() = default; - -void Menu::cleanup() -{ - stop(m_subscriptions); -} - -void Menu::start(uint id) -{ - if (m_subscriptions.contains(id)) { - return; - } - - // TODO watch service disappearing? - - // dbus-send --print-reply --session --dest=:1.103 /org/libreoffice/window/104857641/menus/menubar org.gtk.Menus.Start array:uint32:0 - - QDBusMessage msg = QDBusMessage::createMethodCall(m_serviceName, m_objectPath, s_orgGtkMenus, QStringLiteral("Start")); - msg.setArguments({QVariant::fromValue(QList{id})}); - - QDBusPendingReply reply = QDBusConnection::sessionBus().asyncCall(msg); - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); - connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, id](QDBusPendingCallWatcher *watcher) { - QScopedPointer watcherPtr(watcher); - - QDBusPendingReply reply = *watcherPtr; - if (reply.isError()) { - qDebug() << "Failed to start subscription to" << id << "on" << m_serviceName << "at" << m_objectPath << reply.error(); - emit failedToSubscribe(id); - } else { - const bool hadMenu = !m_menus.isEmpty(); - - const auto menus = reply.value(); - for (const auto &menu : menus) { - m_menus[menu.id].append(menus); - } - - // LibreOffice on startup fails to give us some menus right away, we'll also subscribe in onMenuChanged() if necessary - if (menus.isEmpty()) { - qDebug() << "Got an empty menu for" << id << "on" << m_serviceName << "at" << m_objectPath; - return; - } - - // TODO are we subscribed to all it returns or just to the ones we requested? - m_subscriptions.append(id); - - // do we have a menu now? let's tell everyone - if (!hadMenu && !m_menus.isEmpty()) { - emit menuAppeared(); - } - - emit subscribed(id); - } - }); -} - -void Menu::stop(const QList &ids) -{ - QDBusMessage msg = QDBusMessage::createMethodCall(m_serviceName, m_objectPath, s_orgGtkMenus, QStringLiteral("End")); - msg.setArguments({ - QVariant::fromValue(ids) // don't let it unwrap it, hence in a variant - }); - - QDBusPendingReply reply = QDBusConnection::sessionBus().asyncCall(msg); - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); - connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, ids](QDBusPendingCallWatcher *watcher) { - QDBusPendingReply reply = *watcher; - if (reply.isError()) { - qDebug() << "Failed to stop subscription to" << ids << "on" << m_serviceName << "at" << m_objectPath << reply.error(); - } else { - // remove all subscriptions that we unsubscribed from - // TODO is there a nicer algorithm for that? - // TODO remove all m_menus also? - m_subscriptions.erase( - std::remove_if(m_subscriptions.begin(), m_subscriptions.end(), [ids](uint subscription) { - return ids.contains(subscription); - }), - m_subscriptions.end()); - - if (m_subscriptions.isEmpty()) { - emit menuDisappeared(); - } - } - watcher->deleteLater(); - }); -} - -bool Menu::hasMenu() const -{ - return !m_menus.isEmpty(); -} - -bool Menu::hasSubscription(uint subscription) const -{ - return m_subscriptions.contains(subscription); -} - -GMenuItem Menu::getSection(int id, bool *ok) const -{ - int subscription; - int section; - int index; - Utils::intToTreeStructure(id, subscription, section, index); - return getSection(subscription, section, ok); -} - -GMenuItem Menu::getSection(int subscription, int section, bool *ok) const -{ - const auto menu = m_menus.value(subscription); - - auto it = std::find_if(menu.begin(), menu.end(), [section](const GMenuItem &item) { - return item.section == section; - }); - - if (it == menu.end()) { - if (ok) { - *ok = false; - } - return GMenuItem(); - } - - if (ok) { - *ok = true; - } - return *it; -} - -QVariantMap Menu::getItem(int id) const -{ - int subscription; - int section; - int index; - Utils::intToTreeStructure(id, subscription, section, index); - return getItem(subscription, section, index); -} - -QVariantMap Menu::getItem(int subscription, int sectionId, int index) const -{ - bool ok; - const GMenuItem section = getSection(subscription, sectionId, &ok); - - if (!ok) { - return QVariantMap(); - } - - const auto items = section.items; - - if (items.count() < index) { - qDebug() << "Cannot get action" << subscription << sectionId << index << "which is out of bounds"; - return QVariantMap(); - } - - // 0 is the menu itself, items start at 1 - return items.at(index - 1); -} - -void Menu::onMenuChanged(const GMenuChangeList &changes) -{ - const bool hadMenu = !m_menus.isEmpty(); - - QVector dirtyMenus; - QVector dirtyItems; - - for (const auto &change : changes) { - auto updateSection = [&](GMenuItem §ion) { - // Check if the amount of inserted items is identical to the items to be removed, - // just update the existing items and signal a change for that. - // LibreOffice tends to do that e.g. to update its Undo menu entry - if (change.itemsToRemoveCount == change.itemsToInsert.count()) { - for (int i = 0; i < change.itemsToInsert.count(); ++i) { - const auto &newItem = change.itemsToInsert.at(i); - - section.items[change.changePosition + i] = newItem; - - // 0 is the menu itself, items start at 1 - dirtyItems.append(Utils::treeStructureToInt(change.subscription, change.menu, change.changePosition + i + 1)); - } - } else { - for (int i = 0; i < change.itemsToRemoveCount; ++i) { - section.items.removeAt(change.changePosition); // TODO bounds check - } - - for (int i = 0; i < change.itemsToInsert.count(); ++i) { - section.items.insert(change.changePosition + i, change.itemsToInsert.at(i)); - } - - dirtyMenus.append(Utils::treeStructureToInt(change.subscription, change.menu, 0)); - } - }; - - // shouldn't happen, it says only Start() subscribes to changes - if (!m_subscriptions.contains(change.subscription)) { - qDebug() << "Got menu change for menu" << change.subscription << "that we are not subscribed to, subscribing now"; - // LibreOffice doesn't give us a menu right away but takes a while and then signals us a change - start(change.subscription); - continue; - } - - auto &menu = m_menus[change.subscription]; - - bool sectionFound = false; - // TODO findSectionRef - for (GMenuItem §ion : menu) { - if (section.section != change.menu) { - continue; - } - - qDebug() << "Updating existing section" << change.menu << "in subscription" << change.subscription; - - sectionFound = true; - updateSection(section); - break; - } - - // Insert new section - if (!sectionFound) { - qDebug() << "Creating new section" << change.menu << "in subscription" << change.subscription; - - if (change.itemsToRemoveCount > 0) { - qDebug() << "Menu change requested to remove items from a new (and as such empty) section"; - } - - GMenuItem newSection; - newSection.id = change.subscription; - newSection.section = change.menu; - updateSection(newSection); - menu.append(newSection); - } - } - - // do we have a menu now? let's tell everyone - if (!hadMenu && !m_menus.isEmpty()) { - emit menuAppeared(); - } else if (hadMenu && m_menus.isEmpty()) { - emit menuDisappeared(); - } - - if (!dirtyItems.isEmpty()) { - emit itemsChanged(dirtyItems); - } - - emit menusChanged(dirtyMenus); -} - -void Menu::actionsChanged(const QStringList &dirtyActions, const QString &prefix) -{ - auto forEachMenuItem = [this](const std::function &cb) { - for (auto it = m_menus.constBegin(), end = m_menus.constEnd(); it != end; ++it) { - const int subscription = it.key(); - - for (const auto &menu : it.value()) { - const int section = menu.section; - - int count = 0; - - const auto items = menu.items; - for (const auto &item : items) { - ++count; // 0 is a menu, entries start at 1 - - if (!cb(subscription, section, count, item)) { - goto loopExit; // hell yeah - break; - } - } - } - } - - loopExit: // loop exit - return; - }; - - // now find in which menus these actions are and emit a change accordingly - QVector dirtyItems; - - for (const QString &action : dirtyActions) { - const QString prefixedAction = prefix + action; - - forEachMenuItem([&prefixedAction, &dirtyItems](int subscription, int section, int index, const QVariantMap &item) { - const QString actionName = Utils::itemActionName(item); - - if (actionName == prefixedAction) { - dirtyItems.append(Utils::treeStructureToInt(subscription, section, index)); - return false; // break - } - - return true; // continue - }); - } - - if (!dirtyItems.isEmpty()) { - emit itemsChanged(dirtyItems); - } -} diff --git a/gmenuproxy/menu.h b/gmenuproxy/menu.h deleted file mode 100644 index d19b666..0000000 --- a/gmenuproxy/menu.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Kai Uwe Broulik - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#pragma once - -#include -#include -#include - -#include "./extend/dbusmenutypes_p.h" -#include "gdbusmenutypes_p.h" - -class Menu : public QObject -{ - Q_OBJECT - -public: - Menu(const QString &serviceName, const QString &objectPath, QObject *parent = nullptr); - ~Menu() override; - - void init(); - void cleanup(); - - void start(uint id); - void stop(const QList &ids); - - bool hasMenu() const; - bool hasSubscription(uint subscription) const; - - GMenuItem getSection(int id, bool *ok = nullptr) const; - GMenuItem getSection(int subscription, int sectionId, bool *ok = nullptr) const; - - QVariantMap getItem(int id) const; // bool ok argument? - QVariantMap getItem(int subscription, int sectionId, int id) const; - -public slots: - void actionsChanged(const QStringList &dirtyActions, const QString &prefix); - -Q_SIGNALS: - void menuAppeared(); // emitted the first time a menu was successfully loaded - void menuDisappeared(); - - void subscribed(uint id); - void failedToSubscribe(uint id); - - void itemsChanged(const QVector &itemIds); - void menusChanged(const QVector &menuIds); - -private slots: - void onMenuChanged(const GMenuChangeList &changes); - -private: - void initMenu(); - - void menuChanged(const GMenuChangeList &changes); - - // QSet? - QList m_subscriptions; // keeps track of which menu trees we're subscribed to - - QHash m_menus; - - QString m_serviceName; - QString m_objectPath; -}; diff --git a/gmenuproxy/menuproxy.cpp b/gmenuproxy/menuproxy.cpp deleted file mode 100644 index 69f5604..0000000 --- a/gmenuproxy/menuproxy.cpp +++ /dev/null @@ -1,388 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Kai Uwe Broulik - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#include "menuproxy.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// #include -#include -// #include -#include -#include -#include - -#include - -#include "window.h" - -static const QString s_ourServiceName = QStringLiteral("org.kde.plasma.gmenu_dbusmenu_proxy"); - -static const QString s_dbusMenuRegistrar = QStringLiteral("com.canonical.AppMenu.Registrar"); - -static const QByteArray s_gtkUniqueBusName = QByteArrayLiteral("_GTK_UNIQUE_BUS_NAME"); - -static const QByteArray s_gtkApplicationObjectPath = QByteArrayLiteral("_GTK_APPLICATION_OBJECT_PATH"); -static const QByteArray s_unityObjectPath = QByteArrayLiteral("_UNITY_OBJECT_PATH"); -static const QByteArray s_gtkWindowObjectPath = QByteArrayLiteral("_GTK_WINDOW_OBJECT_PATH"); -static const QByteArray s_gtkMenuBarObjectPath = QByteArrayLiteral("_GTK_MENUBAR_OBJECT_PATH"); -// that's the generic app menu with Help and Options and will be used if window doesn't have a fully-blown menu bar -static const QByteArray s_gtkAppMenuObjectPath = QByteArrayLiteral("_GTK_APP_MENU_OBJECT_PATH"); - -static const QByteArray s_kdeNetWmAppMenuServiceName = QByteArrayLiteral("_KDE_NET_WM_APPMENU_SERVICE_NAME"); -static const QByteArray s_kdeNetWmAppMenuObjectPath = QByteArrayLiteral("_KDE_NET_WM_APPMENU_OBJECT_PATH"); - -static const QString s_gtkModules = QStringLiteral("gtk-modules"); -static const QString s_appMenuGtkModule = QStringLiteral("appmenu-gtk-module"); - -MenuProxy::MenuProxy() - : QObject() - , m_xConnection(qGuiApp->nativeInterface()->connection()) - , m_serviceWatcher(new QDBusServiceWatcher(this)) - , m_gtk2RcWatch(new KDirWatch(this)) - , m_writeGtk2SettingsTimer(new QTimer(this)) -{ - m_serviceWatcher->setConnection(QDBusConnection::sessionBus()); - m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration | QDBusServiceWatcher::WatchForRegistration); - m_serviceWatcher->addWatchedService(s_dbusMenuRegistrar); - - connect(m_serviceWatcher, &QDBusServiceWatcher::serviceRegistered, this, [this](const QString &service) { - Q_UNUSED(service); - qDebug() << "Global menu service became available, starting"; - init(); - }); - connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, [this](const QString &service) { - Q_UNUSED(service); - qDebug() << "Global menu service disappeared, cleaning up"; - teardown(); - }); - - // It's fine to do a blocking call here as we're a separate binary with no UI - if (QDBusConnection::sessionBus().interface()->isServiceRegistered(s_dbusMenuRegistrar)) { - qDebug() << "Global menu service is running, starting right away"; - init(); - } else { - qDebug() << "No global menu service available, waiting for it to start before doing anything"; - - // be sure when started to restore gtk menus when there's no dbus menu around in case we crashed - enableGtkSettings(false); - } - - // kde-gtk-config just deletes and re-creates the gtkrc-2.0, watch this and add our config to it again - m_writeGtk2SettingsTimer->setSingleShot(true); - m_writeGtk2SettingsTimer->setInterval(1000); - connect(m_writeGtk2SettingsTimer, &QTimer::timeout, this, &MenuProxy::writeGtk2Settings); - - auto startGtk2SettingsTimer = [this] { - if (!m_writeGtk2SettingsTimer->isActive()) { - m_writeGtk2SettingsTimer->start(); - } - }; - - connect(m_gtk2RcWatch, &KDirWatch::created, this, startGtk2SettingsTimer); - connect(m_gtk2RcWatch, &KDirWatch::dirty, this, startGtk2SettingsTimer); - m_gtk2RcWatch->addFile(gtkRc2Path()); -} - -MenuProxy::~MenuProxy() -{ - teardown(); -} - -bool MenuProxy::init() -{ - if (!QDBusConnection::sessionBus().registerService(s_ourServiceName)) { - qDebug() << "Failed to register DBus service" << s_ourServiceName; - return false; - } - - enableGtkSettings(true); - - connect(KX11Extras::self(), &KX11Extras::windowAdded, this, &MenuProxy::onWindowAdded); - connect(KX11Extras::self(), &KX11Extras::windowRemoved, this, &MenuProxy::onWindowRemoved); - - const auto windows = KX11Extras::windows(); - for (WId id : windows) { - onWindowAdded(id); - } - - if (m_windows.isEmpty()) { - qDebug() << "Up and running but no windows with menus in sight"; - } - - return true; -} - -void MenuProxy::teardown() -{ - enableGtkSettings(false); - - QDBusConnection::sessionBus().unregisterService(s_ourServiceName); - - disconnect(KX11Extras::self(), &KX11Extras::windowAdded, this, &MenuProxy::onWindowAdded); - disconnect(KX11Extras::self(), &KX11Extras::windowRemoved, this, &MenuProxy::onWindowRemoved); - - qDeleteAll(m_windows); - m_windows.clear(); -} - -void MenuProxy::enableGtkSettings(bool enable) -{ - m_enabled = enable; - - writeGtk2Settings(); - writeGtk3Settings(); - - // TODO use gconf/dconf directly or at least signal a change somehow? -} - -QString MenuProxy::gtkRc2Path() -{ - return QDir::homePath() + QLatin1String("/.gtkrc-2.0"); -} - -QString MenuProxy::gtk3SettingsIniPath() -{ - return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String("/gtk-3.0/settings.ini"); -} - -void MenuProxy::writeGtk2Settings() -{ - QFile rcFile(gtkRc2Path()); - if (!rcFile.exists()) { - // Don't create it here, that would break writing default GTK-2.0 settings on first login, - // as the gtkbreeze kconf_update script only does so if it does not exist - return; - } - - qDebug() << "Writing gtkrc-2.0 to" << (m_enabled ? "enable" : "disable") << "global menu support"; - - if (!rcFile.open(QIODevice::ReadWrite | QIODevice::Text)) { - return; - } - - QByteArray content; - - QStringList gtkModules; - - while (!rcFile.atEnd()) { - const QByteArray rawLine = rcFile.readLine(); - - const QString line = QString::fromUtf8(rawLine.trimmed()); - - if (!line.startsWith(s_gtkModules)) { - // keep line as-is - content += rawLine; - continue; - } - - const int equalSignIdx = line.indexOf(QLatin1Char('=')); - if (equalSignIdx < 1) { - continue; - } - -#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) - gtkModules = line.mid(equalSignIdx + 1).split(QLatin1Char(':'), QString::SkipEmptyParts); -#else - gtkModules = line.mid(equalSignIdx + 1).split(QLatin1Char(':'), Qt::SkipEmptyParts); -#endif - - break; - } - - addOrRemoveAppMenuGtkModule(gtkModules); - - if (!gtkModules.isEmpty()) { - content += QStringLiteral("%1=%2").arg(s_gtkModules, gtkModules.join(QLatin1Char(':'))).toUtf8(); - } - - qDebug() << " gtk-modules:" << gtkModules; - - m_gtk2RcWatch->stopScan(); - - // now write the new contents of the file - rcFile.resize(0); - rcFile.write(content); - rcFile.close(); - - m_gtk2RcWatch->startScan(); -} - -void MenuProxy::writeGtk3Settings() -{ - qDebug() << "Writing gtk-3.0/settings.ini" << (m_enabled ? "enable" : "disable") << "global menu support"; - - // mostly taken from kde-gtk-config - QSettings cfg(gtk3SettingsIniPath(), QSettings::IniFormat); - cfg.beginGroup(QStringLiteral("Settings")); - - QStringList gtkModules = cfg.value(QStringLiteral("gtk-modules")).toString().split(QLatin1Char(':')); - addOrRemoveAppMenuGtkModule(gtkModules); - - if (!gtkModules.isEmpty()) { - cfg.setValue(QStringLiteral("gtk-modules"), gtkModules.join(QLatin1Char(':'))); - } else { - cfg.remove(QStringLiteral("gtk-modules")); - } - - qDebug() << " gtk-modules:" << gtkModules; - - if (m_enabled) { - cfg.setValue(QStringLiteral("gtk-shell-shows-menubar"), 1); - } else { - cfg.remove(QStringLiteral("gtk-shell-shows-menubar")); - } - - qDebug() << " gtk-shell-shows-menubar:" << (m_enabled ? 1 : 0); - - cfg.sync(); -} - -void MenuProxy::addOrRemoveAppMenuGtkModule(QStringList &list) -{ - if (m_enabled && !list.contains(s_appMenuGtkModule)) { - list.append(s_appMenuGtkModule); - } else if (!m_enabled) { - list.removeAll(s_appMenuGtkModule); - } -} - -void MenuProxy::onWindowAdded(WId id) -{ - if (m_windows.contains(id)) { - return; - } - - KWindowInfo info(id, NET::WMWindowType); - - NET::WindowType wType = info.windowType(NET::NormalMask | NET::DesktopMask | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask - | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask); - - // Only top level windows typically have a menu bar, dialogs, such as settings don't - if (wType != NET::Normal) { - qDebug() << "Ignoring window" << id << "of type" << wType; - return; - } - - const QString serviceName = QString::fromUtf8(getWindowPropertyString(id, s_gtkUniqueBusName)); - - if (serviceName.isEmpty()) { - return; - } - - const QString applicationObjectPath = QString::fromUtf8(getWindowPropertyString(id, s_gtkApplicationObjectPath)); - const QString unityObjectPath = QString::fromUtf8(getWindowPropertyString(id, s_unityObjectPath)); - const QString windowObjectPath = QString::fromUtf8(getWindowPropertyString(id, s_gtkWindowObjectPath)); - - const QString applicationMenuObjectPath = QString::fromUtf8(getWindowPropertyString(id, s_gtkAppMenuObjectPath)); - const QString menuBarObjectPath = QString::fromUtf8(getWindowPropertyString(id, s_gtkMenuBarObjectPath)); - - if (applicationMenuObjectPath.isEmpty() && menuBarObjectPath.isEmpty()) { - return; - } - - Window *window = new Window(serviceName); - window->setWinId(id); - window->setApplicationObjectPath(applicationObjectPath); - window->setUnityObjectPath(unityObjectPath); - window->setWindowObjectPath(windowObjectPath); - window->setApplicationMenuObjectPath(applicationMenuObjectPath); - window->setMenuBarObjectPath(menuBarObjectPath); - m_windows.insert(id, window); - - connect(window, &Window::requestWriteWindowProperties, this, [this, window] { - Q_ASSERT(!window->proxyObjectPath().isEmpty()); - - writeWindowProperty(window->winId(), s_kdeNetWmAppMenuServiceName, s_ourServiceName.toUtf8()); - writeWindowProperty(window->winId(), s_kdeNetWmAppMenuObjectPath, window->proxyObjectPath().toUtf8()); - }); - connect(window, &Window::requestRemoveWindowProperties, this, [this, window] { - writeWindowProperty(window->winId(), s_kdeNetWmAppMenuServiceName, QByteArray()); - writeWindowProperty(window->winId(), s_kdeNetWmAppMenuObjectPath, QByteArray()); - }); - - window->init(); -} - -void MenuProxy::onWindowRemoved(WId id) -{ - // no need to cleanup() (which removes window properties) when the window is gone, delete right away - delete m_windows.take(id); -} - -QByteArray MenuProxy::getWindowPropertyString(WId id, const QByteArray &name) -{ - QByteArray value; - - auto atom = getAtom(name); - if (atom == XCB_ATOM_NONE) { - return value; - } - - // GTK properties aren't XCB_ATOM_STRING but a custom one - auto utf8StringAtom = getAtom(QByteArrayLiteral("UTF8_STRING")); - - static const long MAX_PROP_SIZE = 10000; - auto propertyCookie = xcb_get_property(m_xConnection, false, id, atom, utf8StringAtom, 0, MAX_PROP_SIZE); - QScopedPointer propertyReply(xcb_get_property_reply(m_xConnection, propertyCookie, nullptr)); - if (propertyReply.isNull()) { - qDebug() << "XCB property reply for atom" << name << "on" << id << "was null"; - return value; - } - - if (propertyReply->type == utf8StringAtom && propertyReply->format == 8 && propertyReply->value_len > 0) { - const char *data = (const char *)xcb_get_property_value(propertyReply.data()); - int len = propertyReply->value_len; - if (data) { - value = QByteArray(data, data[len - 1] ? len : len - 1); - } - } - - return value; -} - -void MenuProxy::writeWindowProperty(WId id, const QByteArray &name, const QByteArray &value) -{ - auto atom = getAtom(name); - if (atom == XCB_ATOM_NONE) { - return; - } - - if (value.isEmpty()) { - xcb_delete_property(m_xConnection, id, atom); - } else { - xcb_change_property(m_xConnection, XCB_PROP_MODE_REPLACE, id, atom, XCB_ATOM_STRING, 8, value.length(), value.constData()); - } -} - -xcb_atom_t MenuProxy::getAtom(const QByteArray &name) -{ - static QHash s_atoms; - - auto atom = s_atoms.value(name, XCB_ATOM_NONE); - if (atom == XCB_ATOM_NONE) { - const xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom(m_xConnection, false, name.length(), name.constData()); - QScopedPointer atomReply(xcb_intern_atom_reply(m_xConnection, atomCookie, nullptr)); - if (!atomReply.isNull()) { - atom = atomReply->atom; - if (atom != XCB_ATOM_NONE) { - s_atoms.insert(name, atom); - } - } - } - - return atom; -} diff --git a/gmenuproxy/menuproxy.h b/gmenuproxy/menuproxy.h deleted file mode 100644 index 7ca4cb1..0000000 --- a/gmenuproxy/menuproxy.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Kai Uwe Broulik - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#pragma once - -#include -#include -#include -#include // for WId - -#include - -class QDBusServiceWatcher; -class QTimer; - -class KDirWatch; - -class Window; - -class MenuProxy : public QObject -{ - Q_OBJECT - -public: - MenuProxy(); - ~MenuProxy() override; - -private Q_SLOTS: - void onWindowAdded(WId id); - void onWindowRemoved(WId id); - -private: - bool init(); - void teardown(); - - static QString gtkRc2Path(); - static QString gtk3SettingsIniPath(); - - void enableGtkSettings(bool enabled); - - void writeGtk2Settings(); - void writeGtk3Settings(); - - void addOrRemoveAppMenuGtkModule(QStringList &list); - - xcb_connection_t *m_xConnection; - - QByteArray getWindowPropertyString(WId id, const QByteArray &name); - void writeWindowProperty(WId id, const QByteArray &name, const QByteArray &value); - xcb_atom_t getAtom(const QByteArray &name); - - QHash m_windows; - - QDBusServiceWatcher *m_serviceWatcher; - - KDirWatch *m_gtk2RcWatch; - QTimer *m_writeGtk2SettingsTimer; - - bool m_enabled = false; -}; diff --git a/gmenuproxy/utils.cpp b/gmenuproxy/utils.cpp deleted file mode 100644 index 9517e6f..0000000 --- a/gmenuproxy/utils.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Kai Uwe Broulik - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#include "utils.h" - -int Utils::treeStructureToInt(int subscription, int section, int index) -{ - return subscription * 1000000 + section * 1000 + index; -} - -void Utils::intToTreeStructure(int source, int &subscription, int §ion, int &index) -{ - // TODO some better math :) or bit shifting or something - index = source % 1000; - section = (source / 1000) % 1000; - subscription = source / 1000000; -} - -QString Utils::itemActionName(const QVariantMap &item) -{ - QString actionName = item.value(QStringLiteral("action")).toString(); - if (actionName.isEmpty()) { - actionName = item.value(QStringLiteral("submenu-action")).toString(); - } - return actionName; -} diff --git a/gmenuproxy/utils.h b/gmenuproxy/utils.h deleted file mode 100644 index 513783d..0000000 --- a/gmenuproxy/utils.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Kai Uwe Broulik - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#pragma once - -#include -#include - -namespace Utils -{ -int treeStructureToInt(int subscription, int section, int index); -void intToTreeStructure(int source, int &subscription, int §ion, int &index); - -QString itemActionName(const QVariantMap &item); - -} diff --git a/gmenuproxy/window.cpp b/gmenuproxy/window.cpp deleted file mode 100644 index 7989de4..0000000 --- a/gmenuproxy/window.cpp +++ /dev/null @@ -1,653 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Kai Uwe Broulik - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#include "window.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "actions.h" -#include "dbusmenuadaptor.h" -#include "icons.h" -#include "menu.h" -#include "utils.h" - -#include "./extend/dbusmenushortcut_p.h" - -static const QString s_orgGtkActions = QStringLiteral("org.gtk.Actions"); -static const QString s_orgGtkMenus = QStringLiteral("org.gtk.Menus"); - -static const QString s_applicationActionsPrefix = QStringLiteral("app."); -static const QString s_unityActionsPrefix = QStringLiteral("unity."); -static const QString s_windowActionsPrefix = QStringLiteral("win."); - -Window::Window(const QString &serviceName) - : QObject() - , m_serviceName(serviceName) -{ - qDebug() << "Created menu on" << serviceName; - - Q_ASSERT(!serviceName.isEmpty()); - - GDBusMenuTypes_register(); - DBusMenuTypes_register(); -} - -Window::~Window() = default; - -void Window::init() -{ - qDebug() << "Inited window with menu for" << m_winId << "on" << m_serviceName << "at app" << m_applicationObjectPath << "win" - << m_windowObjectPath << "unity" << m_unityObjectPath; - - if (!m_applicationMenuObjectPath.isEmpty()) { - m_applicationMenu = new Menu(m_serviceName, m_applicationMenuObjectPath, this); - connect(m_applicationMenu, &Menu::menuAppeared, this, &Window::updateWindowProperties); - connect(m_applicationMenu, &Menu::menuDisappeared, this, &Window::updateWindowProperties); - connect(m_applicationMenu, &Menu::subscribed, this, &Window::onMenuSubscribed); - // basically so it replies on DBus no matter what - connect(m_applicationMenu, &Menu::failedToSubscribe, this, &Window::onMenuSubscribed); - connect(m_applicationMenu, &Menu::itemsChanged, this, &Window::menuItemsChanged); - connect(m_applicationMenu, &Menu::menusChanged, this, &Window::menuChanged); - } - - if (!m_menuBarObjectPath.isEmpty()) { - m_menuBar = new Menu(m_serviceName, m_menuBarObjectPath, this); - connect(m_menuBar, &Menu::menuAppeared, this, &Window::updateWindowProperties); - connect(m_menuBar, &Menu::menuDisappeared, this, &Window::updateWindowProperties); - connect(m_menuBar, &Menu::subscribed, this, &Window::onMenuSubscribed); - connect(m_menuBar, &Menu::failedToSubscribe, this, &Window::onMenuSubscribed); - connect(m_menuBar, &Menu::itemsChanged, this, &Window::menuItemsChanged); - connect(m_menuBar, &Menu::menusChanged, this, &Window::menuChanged); - } - - if (!m_applicationObjectPath.isEmpty()) { - m_applicationActions = new Actions(m_serviceName, m_applicationObjectPath, this); - connect(m_applicationActions, &Actions::actionsChanged, this, [this](const QStringList &dirtyActions) { - onActionsChanged(dirtyActions, s_applicationActionsPrefix); - }); - connect(m_applicationActions, &Actions::loaded, this, [this] { - if (m_menuInited) { - onActionsChanged(m_applicationActions->getAll().keys(), s_applicationActionsPrefix); - } else { - initMenu(); - } - }); - m_applicationActions->load(); - } - - if (!m_unityObjectPath.isEmpty()) { - m_unityActions = new Actions(m_serviceName, m_unityObjectPath, this); - connect(m_unityActions, &Actions::actionsChanged, this, [this](const QStringList &dirtyActions) { - onActionsChanged(dirtyActions, s_unityActionsPrefix); - }); - connect(m_unityActions, &Actions::loaded, this, [this] { - if (m_menuInited) { - onActionsChanged(m_unityActions->getAll().keys(), s_unityActionsPrefix); - } else { - initMenu(); - } - }); - m_unityActions->load(); - } - - if (!m_windowObjectPath.isEmpty()) { - m_windowActions = new Actions(m_serviceName, m_windowObjectPath, this); - connect(m_windowActions, &Actions::actionsChanged, this, [this](const QStringList &dirtyActions) { - onActionsChanged(dirtyActions, s_windowActionsPrefix); - }); - connect(m_windowActions, &Actions::loaded, this, [this] { - if (m_menuInited) { - onActionsChanged(m_windowActions->getAll().keys(), s_windowActionsPrefix); - } else { - initMenu(); - } - }); - m_windowActions->load(); - } -} - -WId Window::winId() const -{ - return m_winId; -} - -void Window::setWinId(WId winId) -{ - m_winId = winId; -} - -QString Window::serviceName() const -{ - return m_serviceName; -} - -QString Window::applicationObjectPath() const -{ - return m_applicationObjectPath; -} - -void Window::setApplicationObjectPath(const QString &applicationObjectPath) -{ - m_applicationObjectPath = applicationObjectPath; -} - -QString Window::unityObjectPath() const -{ - return m_unityObjectPath; -} - -void Window::setUnityObjectPath(const QString &unityObjectPath) -{ - m_unityObjectPath = unityObjectPath; -} - -QString Window::applicationMenuObjectPath() const -{ - return m_applicationMenuObjectPath; -} - -void Window::setApplicationMenuObjectPath(const QString &applicationMenuObjectPath) -{ - m_applicationMenuObjectPath = applicationMenuObjectPath; -} - -QString Window::menuBarObjectPath() const -{ - return m_menuBarObjectPath; -} - -void Window::setMenuBarObjectPath(const QString &menuBarObjectPath) -{ - m_menuBarObjectPath = menuBarObjectPath; -} - -QString Window::windowObjectPath() const -{ - return m_windowObjectPath; -} - -void Window::setWindowObjectPath(const QString &windowObjectPath) -{ - m_windowObjectPath = windowObjectPath; -} - -QString Window::currentMenuObjectPath() const -{ - return m_currentMenuObjectPath; -} - -QString Window::proxyObjectPath() const -{ - return m_proxyObjectPath; -} - -void Window::initMenu() -{ - if (m_menuInited) { - return; - } - - if (!registerDBusObject()) { - return; - } - - // appmenu-gtk-module always announces a menu bar on every GTK window even if there is none - // so we subscribe to the menu bar as soon as it shows up so we can figure out - // if we have a menu bar, an app menu, or just nothing - if (m_applicationMenu) { - m_applicationMenu->start(0); - } - - if (m_menuBar) { - m_menuBar->start(0); - } - - m_menuInited = true; -} - -void Window::menuItemsChanged(const QVector &itemIds) -{ - if (qobject_cast(sender()) != m_currentMenu) { - return; - } - - DBusMenuItemList items; - - for (uint id : itemIds) { - const auto newItem = m_currentMenu->getItem(id); - - DBusMenuItem dBusItem{// 0 is menu, items start at 1 - static_cast(id), - gMenuToDBusMenuProperties(newItem)}; - items.append(dBusItem); - } - - emit ItemsPropertiesUpdated(items, {}); -} - -void Window::menuChanged(const QVector &menuIds) -{ - if (qobject_cast(sender()) != m_currentMenu) { - return; - } - - for (uint menu : menuIds) { - emit LayoutUpdated(3 /*revision*/, menu); - } -} - -void Window::onMenuSubscribed(uint id) -{ - // When it was a delayed GetLayout request, send the reply now - const auto pendingReplies = m_pendingGetLayouts.values(id); - if (!pendingReplies.isEmpty()) { - for (const auto &pendingReply : pendingReplies) { - if (pendingReply.type() != QDBusMessage::InvalidMessage) { - auto reply = pendingReply.createReply(); - - DBusMenuLayoutItem item; - uint revision = GetLayout(Utils::treeStructureToInt(id, 0, 0), 0, {}, item); - - reply << revision << QVariant::fromValue(item); - - QDBusConnection::sessionBus().send(reply); - } - } - m_pendingGetLayouts.remove(id); - } else { - emit LayoutUpdated(2 /*revision*/, id); - } -} - -bool Window::getAction(const QString &name, GMenuAction &action) const -{ - QString lookupName; - Actions *actions = getActionsForAction(name, lookupName); - - if (!actions) { - return false; - } - - return actions->get(lookupName, action); -} - -void Window::triggerAction(const QString &name, const QVariant &target, uint timestamp) -{ - QString lookupName; - Actions *actions = getActionsForAction(name, lookupName); - if (!actions) { - return; - } - - actions->trigger(lookupName, target, timestamp); -} - -Actions *Window::getActionsForAction(const QString &name, QString &lookupName) const -{ - if (name.startsWith(QLatin1String("app."))) { - lookupName = name.mid(4); - return m_applicationActions; - } else if (name.startsWith(QLatin1String("unity."))) { - lookupName = name.mid(6); - return m_unityActions; - } else if (name.startsWith(QLatin1String("win."))) { - lookupName = name.mid(4); - return m_windowActions; - } - - return nullptr; -} - -void Window::onActionsChanged(const QStringList &dirty, const QString &prefix) -{ - if (m_applicationMenu) { - m_applicationMenu->actionsChanged(dirty, prefix); - } - if (m_menuBar) { - m_menuBar->actionsChanged(dirty, prefix); - } -} - -bool Window::registerDBusObject() -{ - Q_ASSERT(m_proxyObjectPath.isEmpty()); - - static int menus = 0; - ++menus; - - new DbusmenuAdaptor(this); - - const QString objectPath = QStringLiteral("/MenuBar/%1").arg(QString::number(menus)); - qDebug() << "Registering DBus object path" << objectPath; - - if (!QDBusConnection::sessionBus().registerObject(objectPath, this)) { - qDebug() << "Failed to register object"; - return false; - } - - m_proxyObjectPath = objectPath; - - return true; -} - -void Window::updateWindowProperties() -{ - const bool hasMenu = ((m_applicationMenu && m_applicationMenu->hasMenu()) || (m_menuBar && m_menuBar->hasMenu())); - - if (!hasMenu) { - emit requestRemoveWindowProperties(); - return; - } - - Menu *oldMenu = m_currentMenu; - Menu *newMenu = qobject_cast(sender()); - // set current menu as needed - if (!m_currentMenu) { - m_currentMenu = newMenu; - // Menu Bar takes precedence over application menu - } else if (m_currentMenu == m_applicationMenu && newMenu == m_menuBar) { - qDebug() << "Switching from application menu to menu bar"; - m_currentMenu = newMenu; - // TODO update layout - } - - if (m_currentMenu != oldMenu) { - // update entire menu now - emit LayoutUpdated(4 /*revision*/, 0); - } - - emit requestWriteWindowProperties(); -} - -// DBus -bool Window::AboutToShow(int id) -{ - // We always request the first time GetLayout is called and keep up-to-date internally - // No need to have us prepare anything here - Q_UNUSED(id); - return false; -} - -void Window::Event(int id, const QString &eventId, const QDBusVariant &data, uint timestamp) -{ - Q_UNUSED(data); - - if (!m_currentMenu) { - return; - } - - // GMenu dbus doesn't have any "opened" or "closed" signals, we'll only handle "clicked" - - if (eventId == QLatin1String("clicked")) { - const QVariantMap item = m_currentMenu->getItem(id); - const QString action = item.value(QStringLiteral("action")).toString(); - const QVariant target = item.value(QStringLiteral("target")); - if (!action.isEmpty()) { - triggerAction(action, target, timestamp); - } - } -} - -DBusMenuItemList Window::GetGroupProperties(const QList &ids, const QStringList &propertyNames) -{ - Q_UNUSED(ids); - Q_UNUSED(propertyNames); - return DBusMenuItemList(); -} - -uint Window::GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, DBusMenuLayoutItem &dbusItem) -{ - Q_UNUSED(recursionDepth); // TODO - Q_UNUSED(propertyNames); - - int subscription; - int sectionId; - int index; - - Utils::intToTreeStructure(parentId, subscription, sectionId, index); - - if (!m_currentMenu) { - return 1; - } - - if (!m_currentMenu->hasSubscription(subscription)) { - // let's serve multiple similar requests in one go once we've processed them - m_pendingGetLayouts.insert(subscription, message()); - setDelayedReply(true); - - m_currentMenu->start(subscription); - return 1; - } - - bool ok; - const GMenuItem section = m_currentMenu->getSection(subscription, sectionId, &ok); - - if (!ok) { - qDebug() << "There is no section on" << subscription << "at" << sectionId << "with" << parentId; - return 1; - } - - // If a particular entry is requested, see what it is and resolve as necessary - // for example the "File" entry on root is 0,0,1 but is a menu reference to e.g. 1,0,0 - // so resolve that and return the correct menu - if (index > 0) { - // non-zero index indicates item within a menu but the index in the list still starts at zero - if (section.items.count() < index) { - qDebug() << "Requested index" << index << "on" << subscription << "at" << sectionId << "with" << parentId << "is out of bounds"; - return 0; - } - - const auto &requestedItem = section.items.at(index - 1); - - auto it = requestedItem.constFind(QStringLiteral(":submenu")); - if (it != requestedItem.constEnd()) { - const GMenuSection gmenuSection = qdbus_cast(it->value()); - return GetLayout(Utils::treeStructureToInt(gmenuSection.subscription, gmenuSection.menu, 0), recursionDepth, propertyNames, dbusItem); - } else { - // TODO - return 0; - } - } - - dbusItem.id = parentId; // TODO - dbusItem.properties = {{QStringLiteral("children-display"), QStringLiteral("submenu")}}; - - int count = 0; - - const auto itemsToBeAdded = section.items; - for (const auto &item : itemsToBeAdded) { - DBusMenuLayoutItem child{ - Utils::treeStructureToInt(section.id, sectionId, ++count), - gMenuToDBusMenuProperties(item), - {} // children - }; - dbusItem.children.append(child); - - // Now resolve section aliases - auto it = item.constFind(QStringLiteral(":section")); - if (it != item.constEnd()) { - // references another place, add it instead - GMenuSection gmenuSection = qdbus_cast(it->value()); - - // remember where the item came from and give it an appropriate ID - // so updates signalled by the app will map to the right place - int originalSubscription = gmenuSection.subscription; - int originalMenu = gmenuSection.menu; - - // TODO start subscription if we don't have it - auto items = m_currentMenu->getSection(gmenuSection.subscription, gmenuSection.menu).items; - - // Check whether it's an alias to an alias - // FIXME make generic/recursive - if (items.count() == 1) { - const auto &aliasedItem = items.constFirst(); - auto findIt = aliasedItem.constFind(QStringLiteral(":section")); - if (findIt != aliasedItem.constEnd()) { - GMenuSection gmenuSection2 = qdbus_cast(findIt->value()); - items = m_currentMenu->getSection(gmenuSection2.subscription, gmenuSection2.menu).items; - - originalSubscription = gmenuSection2.subscription; - originalMenu = gmenuSection2.menu; - } - } - - int aliasedCount = 0; - for (const auto &aliasedItem : qAsConst(items)) { - DBusMenuLayoutItem aliasedChild{ - Utils::treeStructureToInt(originalSubscription, originalMenu, ++aliasedCount), - gMenuToDBusMenuProperties(aliasedItem), - {} // children - }; - dbusItem.children.append(aliasedChild); - } - } - } - - // revision, unused in libdbusmenuqt - return 1; -} - -QDBusVariant Window::GetProperty(int id, const QString &property) -{ - Q_UNUSED(id); - Q_UNUSED(property); - QDBusVariant value; - return value; -} - -QString Window::status() const -{ - return QStringLiteral("normal"); -} - -uint Window::version() const -{ - return 4; -} - -QVariantMap Window::gMenuToDBusMenuProperties(const QVariantMap &source) const -{ - QVariantMap result; - - result.insert(QStringLiteral("label"), source.value(QStringLiteral("label")).toString()); - - if (source.contains(QLatin1String(":section"))) { - result.insert(QStringLiteral("type"), QStringLiteral("separator")); - } - - const bool isMenu = source.contains(QLatin1String(":submenu")); - if (isMenu) { - result.insert(QStringLiteral("children-display"), QStringLiteral("submenu")); - } - - QString accel = source.value(QStringLiteral("accel")).toString(); - if (!accel.isEmpty()) { - QStringList shortcut; - - // TODO use regexp or something - if (accel.contains(QLatin1String("")) || accel.contains(QLatin1String(""))) { - shortcut.append(QStringLiteral("Control")); - accel.remove(QLatin1String("")); - accel.remove(QLatin1String("")); - } - - if (accel.contains(QLatin1String(""))) { - shortcut.append(QStringLiteral("Shift")); - accel.remove(QLatin1String("")); - } - - if (accel.contains(QLatin1String(""))) { - shortcut.append(QStringLiteral("Alt")); - accel.remove(QLatin1String("")); - } - - if (accel.contains(QLatin1String(""))) { - shortcut.append(QStringLiteral("Super")); - accel.remove(QLatin1String("")); - } - - if (!accel.isEmpty()) { - // TODO replace "+" by "plus" and "-" by "minus" - shortcut.append(accel); - - // TODO does gmenu support multiple? - DBusMenuShortcut dbusShortcut; - dbusShortcut.append(shortcut); // don't let it unwrap the list we append - - result.insert(QStringLiteral("shortcut"), QVariant::fromValue(dbusShortcut)); - } - } - - bool enabled = true; - - const QString actionName = Utils::itemActionName(source); - - GMenuAction action; - // if no action is specified this is fine but if there is an action we don't have - // disable the menu entry - bool actionOk = true; - if (!actionName.isEmpty()) { - actionOk = getAction(actionName, action); - enabled = actionOk && action.enabled; - } - - // we used to only send this if not enabled but then dbusmenuimporter does not - // update the enabled state when it changes from disabled to enabled - result.insert(QStringLiteral("enabled"), enabled); - - bool visible = true; - const QString hiddenWhen = source.value(QStringLiteral("hidden-when")).toString(); - if (hiddenWhen == QLatin1String("action-disabled") && (!actionOk || !enabled)) { - visible = false; - } else if (hiddenWhen == QLatin1String("action-missing") && !actionOk) { - visible = false; - // While we have Global Menu we don't have macOS menu (where Quit, Help, etc is separate) - } else if (hiddenWhen == QLatin1String("macos-menubar")) { - visible = true; - } - - result.insert(QStringLiteral("visible"), visible); - - QString icon = source.value(QStringLiteral("icon")).toString(); - if (icon.isEmpty()) { - icon = source.value(QStringLiteral("verb-icon")).toString(); - } - - icon = Icons::actionIcon(actionName); - if (!icon.isEmpty()) { - result.insert(QStringLiteral("icon-name"), icon); - } - - const QVariant target = source.value(QStringLiteral("target")); - - if (actionOk) { - const auto actionStates = action.state; - if (actionStates.count() == 1) { - const auto &actionState = actionStates.first(); - // assume this is a checkbox - if (!isMenu) { - if (actionState.type() == QVariant::Bool) { - result.insert(QStringLiteral("toggle-type"), QStringLiteral("checkbox")); - result.insert(QStringLiteral("toggle-state"), actionState.toBool() ? 1 : 0); - } else if (actionState.type() == QVariant::String) { - result.insert(QStringLiteral("toggle-type"), QStringLiteral("radio")); - result.insert(QStringLiteral("toggle-state"), actionState == target ? 1 : 0); - } - } - } - } - - return result; -} diff --git a/gmenuproxy/window.h b/gmenuproxy/window.h deleted file mode 100644 index 053b41a..0000000 --- a/gmenuproxy/window.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Kai Uwe Broulik - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#pragma once - -#include -#include -#include -#include -#include -#include // for WId - -#include - -#include "./extend/dbusmenutypes_p.h" -#include "gdbusmenutypes_p.h" - -class QDBusVariant; - -class Actions; -class Menu; - -class Window : public QObject, protected QDBusContext -{ - Q_OBJECT - - // DBus - Q_PROPERTY(QString Status READ status) - Q_PROPERTY(uint Version READ version) - -public: - Window(const QString &serviceName); - ~Window() override; - - void init(); - - WId winId() const; - void setWinId(WId winId); - - QString serviceName() const; - - QString applicationObjectPath() const; - void setApplicationObjectPath(const QString &applicationObjectPath); - - QString unityObjectPath() const; - void setUnityObjectPath(const QString &unityObjectPath); - - QString windowObjectPath() const; - void setWindowObjectPath(const QString &windowObjectPath); - - QString applicationMenuObjectPath() const; - void setApplicationMenuObjectPath(const QString &applicationMenuObjectPath); - - QString menuBarObjectPath() const; - void setMenuBarObjectPath(const QString &menuBarObjectPath); - - QString currentMenuObjectPath() const; - - QString proxyObjectPath() const; - - // DBus - bool AboutToShow(int id); - void Event(int id, const QString &eventId, const QDBusVariant &data, uint timestamp); - DBusMenuItemList GetGroupProperties(const QList &ids, const QStringList &propertyNames); - uint GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, DBusMenuLayoutItem &dbusItem); - QDBusVariant GetProperty(int id, const QString &property); - - QString status() const; - uint version() const; - -Q_SIGNALS: - // don't want to pollute X stuff into Menu, let all of that be in MenuProxy - void requestWriteWindowProperties(); - void requestRemoveWindowProperties(); - - // DBus - void ItemActivationRequested(int id, uint timestamp); - void ItemsPropertiesUpdated(const DBusMenuItemList &updatedProps, const DBusMenuItemKeysList &removedProps); - void LayoutUpdated(uint revision, int parent); - -private: - void initMenu(); - - bool registerDBusObject(); - void updateWindowProperties(); - - bool getAction(const QString &name, GMenuAction &action) const; - void triggerAction(const QString &name, const QVariant &target, uint timestamp = 0); - Actions *getActionsForAction(const QString &name, QString &lookupName) const; - - void menuChanged(const QVector &menuIds); - void menuItemsChanged(const QVector &itemIds); - - void onActionsChanged(const QStringList &dirty, const QString &prefix); - void onMenuSubscribed(uint id); - - QVariantMap gMenuToDBusMenuProperties(const QVariantMap &source) const; - - WId m_winId = 0; - QString m_serviceName; // original GMenu service (the gtk app) - - QString m_applicationObjectPath; - QString m_unityObjectPath; - QString m_windowObjectPath; - QString m_applicationMenuObjectPath; - QString m_menuBarObjectPath; - - QString m_currentMenuObjectPath; - - QString m_proxyObjectPath; // our object path on this proxy app - - QMultiHash m_pendingGetLayouts; - - Menu *m_applicationMenu = nullptr; - Menu *m_menuBar = nullptr; - - Menu *m_currentMenu = nullptr; - - Actions *m_applicationActions = nullptr; - Actions *m_unityActions = nullptr; - Actions *m_windowActions = nullptr; - - bool m_menuInited = false; -}; diff --git a/notificationd/CMakeLists.txt b/notificationd/CMakeLists.txt index 436eaf6..702ce51 100644 --- a/notificationd/CMakeLists.txt +++ b/notificationd/CMakeLists.txt @@ -20,8 +20,6 @@ set(SRCS main.cpp qt6_add_dbus_adaptor(DBUS_SOURCES com.cutefish.Notification.xml application.h Application) set_source_files_properties(${DBUS_SOURCES} PROPERTIES SKIP_AUTOGEN ON) -find_package(KF6WindowSystem) - add_executable(cutefish-notificationd ${SRCS} ${DBUS_SOURCES}) target_link_libraries(cutefish-notificationd @@ -29,7 +27,6 @@ target_link_libraries(cutefish-notificationd Qt6::DBus Qt6::Quick Qt6::Widgets - KF6::WindowSystem ) install(TARGETS cutefish-notificationd diff --git a/notificationd/notificationpopup.cpp b/notificationd/notificationpopup.cpp index a49dbee..14fa822 100644 --- a/notificationd/notificationpopup.cpp +++ b/notificationd/notificationpopup.cpp @@ -21,10 +21,6 @@ #include -#include -#include -#include -#include NotificationPopup::NotificationPopup(QQuickView *parent) : QQuickView(parent) @@ -37,10 +33,5 @@ NotificationPopup::NotificationPopup(QQuickView *parent) bool NotificationPopup::eventFilter(QObject *object, QEvent *event) { - if (event->type() == QEvent::Show) { - if (KWindowSystem::isPlatformX11()) - KX11Extras::setState(winId(), NET::SkipTaskbar | NET::SkipPager | NET::SkipSwitcher); - } - return QObject::eventFilter(object, event); } diff --git a/notificationd/notificationwindow.cpp b/notificationd/notificationwindow.cpp index 44ab6f0..fb809c0 100644 --- a/notificationd/notificationwindow.cpp +++ b/notificationd/notificationwindow.cpp @@ -23,10 +23,6 @@ #include -#include -#include -#include -#include NotificationWindow::NotificationWindow(QQuickView *parent) : QQuickView(parent) @@ -41,7 +37,6 @@ NotificationWindow::NotificationWindow(QQuickView *parent) rootContext()->setContextProperty("notificationsModel", NotificationsModel::self()); rootContext()->setContextProperty("historyModel", HistoryModel::self()); - // KWindowEffects::slideWindow(winId(), KWindowEffects::RightEdge); setSource(QUrl("qrc:/qml/NotificationWindow.qml")); setVisible(false); } @@ -67,8 +62,6 @@ bool NotificationWindow::eventFilter(QObject *object, QEvent *event) QQuickView::setVisible(false); } } else if (event->type() == QEvent::Show) { - if (KWindowSystem::isPlatformX11()) - KX11Extras::setState(winId(), NET::SkipTaskbar | NET::SkipPager | NET::SkipSwitcher); HistoryModel::self()->updateTime(); } else if (event->type() == QEvent::Hide) { setMouseGrabEnabled(false); diff --git a/powerman/CMakeLists.txt b/powerman/CMakeLists.txt index 8af828b..15ab708 100644 --- a/powerman/CMakeLists.txt +++ b/powerman/CMakeLists.txt @@ -2,18 +2,6 @@ project(cutefish-powerman) set(TARGET cutefish-powerman) find_package(KF6IdleTime) -find_package(X11) -find_package(XCB - REQUIRED COMPONENTS - XCB - DPMS -) - -set(XCB_LIBS - XCB::XCB - XCB::DPMS -) - set(SOURCES main.cpp application.cpp @@ -43,8 +31,6 @@ target_link_libraries(${TARGET} Qt6::DBus KF6::IdleTime - ${XCB_LIBS} - ${X11_LIBRARIES} ) install(TARGETS ${TARGET} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/powerman/dimdisplayaction.cpp b/powerman/dimdisplayaction.cpp index dd35e91..2fdcb71 100644 --- a/powerman/dimdisplayaction.cpp +++ b/powerman/dimdisplayaction.cpp @@ -24,10 +24,6 @@ #include #include #include -#include - -#include -#include DimDisplayAction::DimDisplayAction(QObject *parent) : Action(parent) @@ -35,12 +31,6 @@ DimDisplayAction::DimDisplayAction(QObject *parent) "/Brightness", "com.cutefish.Brightness", QDBusConnection::sessionBus()) { - if (qGuiApp->nativeInterface()) { - // Disable a default timeout, if any - xcb_dpms_set_timeouts(qGuiApp->nativeInterface()->connection(), 0, 0, 0); - - XSetScreenSaver(qGuiApp->nativeInterface()->display(), 0, 0, 0, 0); - } } void DimDisplayAction::onWakeupFromIdle() diff --git a/sddm-helper/com.cutefish.sddm.helper.pkexec.policy.in b/sddm-helper/com.cutefish.sddm.helper.pkexec.policy.in index 346e66b..52b85c5 100644 --- a/sddm-helper/com.cutefish.sddm.helper.pkexec.policy.in +++ b/sddm-helper/com.cutefish.sddm.helper.pkexec.policy.in @@ -3,8 +3,8 @@ "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd"> - Authentication is required to SDDM DPI - battery + Authentication is required to change the SDDM scale factor + preferences-desktop-display no no diff --git a/sddm-helper/main.cpp b/sddm-helper/main.cpp index 26b2193..19987b1 100644 --- a/sddm-helper/main.cpp +++ b/sddm-helper/main.cpp @@ -30,18 +30,17 @@ int main(int argc, char *argv[]) parser.addHelpOption(); parser.addVersionOption(); - QCommandLineOption dpiOption(QStringLiteral("dpi"), QStringLiteral("Set DPI")); - parser.addOption(dpiOption); - parser.addPositionalArgument("value", "Value"); + QCommandLineOption scaleOption(QStringLiteral("scale"), QStringLiteral("Set greeter scale factor"), + QStringLiteral("factor")); + parser.addOption(scaleOption); parser.process(app); - if (parser.isSet(dpiOption)) { - int value = parser.positionalArguments().value(0).toInt(); - int minValue = 96; - - if (value < minValue) - value = minValue; + if (parser.isSet(scaleOption)) { + bool ok = false; + const qreal value = parser.value(scaleOption).toDouble(&ok); + if (!ok || value < 1.0 || value > 4.0) + return 1; QDir dir("/etc/sddm.conf.d"); @@ -49,9 +48,10 @@ int main(int argc, char *argv[]) dir.mkpath("/etc/sddm.conf.d"); } - QSettings settings("/etc/sddm.conf.d/dpi.conf", QSettings::IniFormat); - settings.beginGroup("X11"); - settings.setValue("ServerArguments", QString("-nolisten tcp -dpi %1").arg(value)); + QSettings settings("/etc/sddm.conf.d/scale.conf", QSettings::IniFormat); + settings.beginGroup("General"); + settings.setValue("GreeterEnvironment", + QStringLiteral("QT_SCALE_FACTOR=%1").arg(value, 0, 'g', 3)); } return 0; diff --git a/session/CMakeLists.txt b/session/CMakeLists.txt index abcc4c3..f4c7623 100644 --- a/session/CMakeLists.txt +++ b/session/CMakeLists.txt @@ -18,8 +18,6 @@ qt6_add_dbus_adaptor(DBUS_SOURCES sessionadaptor SessionAdaptor) set_source_files_properties(${DBUS_SOURCES} PROPERTIES SKIP_AUTOGEN ON) -find_package(KF6WindowSystem) - add_executable(${TARGET} ${SOURCES} ${DBUS_SOURCES}) target_link_libraries(${TARGET} Qt6::Core @@ -27,11 +25,9 @@ target_link_libraries(${TARGET} Qt6::Widgets Qt6::Quick Qt6::DBus - KF6::WindowSystem ) install(TARGETS ${TARGET} DESTINATION ${CMAKE_INSTALL_BINDIR}) -install(FILES cutefish-xsession.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/xsessions/) install(PROGRAMS cutefish-kwin-wayland-session cutefish-wayland-session DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES cutefish-applications.menu DESTINATION /etc/xdg/menus/) install(FILES cutefish-wayland.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions/) diff --git a/session/application.cpp b/session/application.cpp index ebd0606..ce8d214 100644 --- a/session/application.cpp +++ b/session/application.cpp @@ -32,8 +32,6 @@ #include #include -#include - // STL #include @@ -71,8 +69,7 @@ bool isShellVariable(const QByteArray &name) bool isSessionVariable(const QByteArray &name) { // Check is variable is specific to session. - return name == "DISPLAY" || name == "XAUTHORITY" || // - name == "WAYLAND_DISPLAY" || name == "WAYLAND_SOCKET" || // + return name == "WAYLAND_DISPLAY" || name == "WAYLAND_SOCKET" || // name.startsWith("XDG_"); } @@ -87,8 +84,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) , m_processManager(new ProcessManager(this)) , m_networkProxyManager(new NetworkProxyManager) - , m_wayland(false) - , m_startWindowManager(true) { new SessionAdaptor(this); @@ -100,22 +95,11 @@ Application::Application(int &argc, char **argv) parser.setApplicationDescription(QStringLiteral("Cutefish Session")); parser.addHelpOption(); - QCommandLineOption waylandOption(QStringList() << "w" << "wayland" << "Wayland Mode"); - parser.addOption(waylandOption); - QCommandLineOption noWindowManagerOption(QStringList() << "no-wm" << "Do not start a window manager"); - parser.addOption(noWindowManagerOption); parser.process(*this); - m_wayland = parser.isSet(waylandOption) || QGuiApplication::platformName().contains(QStringLiteral("wayland")); - m_startWindowManager = !parser.isSet(noWindowManagerOption); - createConfigDirectory(); - if (!m_wayland) - initKWinConfig(); initLanguage(); initScreenScaleFactors(); - if (!m_wayland) - initXResource(); initEnvironments(); @@ -131,26 +115,12 @@ Application::Application(int &argc, char **argv) // ref plasma importSystemdEnvrionment(); - qunsetenv("XCURSOR_THEME"); - qunsetenv("XCURSOR_SIZE"); - qunsetenv("SESSION_MANAGER"); - m_networkProxyManager->update(); QTimer::singleShot(50, this, &Application::updateUserDirs); QTimer::singleShot(100, m_processManager, &ProcessManager::start); } -bool Application::wayland() const -{ - return m_wayland; -} - -bool Application::startWindowManager() const -{ - return m_startWindowManager; -} - void Application::launch(const QString &exec, const QStringList &args) { QProcess process; @@ -198,6 +168,7 @@ void Application::initEnvironments() qputenv("XDG_SESSION_DESKTOP", "Cutefish"); // Qt + qputenv("QT_QPA_PLATFORM", "wayland"); qputenv("QT_QPA_PLATFORMTHEME", "cutefish"); qputenv("QT_PLATFORM_PLUGIN", "cutefish"); @@ -277,76 +248,6 @@ void Application::initScreenScaleFactors() } } -void Application::initXResource() -{ - QSettings settings(QSettings::UserScope, "cutefishos", "theme"); - qreal scaleFactor = settings.value("PixelRatio", 1.0).toReal(); - int fontDpi = 96 * scaleFactor; - QString cursorTheme = settings.value("CursorTheme", "default").toString(); - int cursorSize = settings.value("CursorSize", 24).toInt() * scaleFactor; - int xftAntialias = settings.value("XftAntialias", 1).toBool(); - QString xftHintStyle = settings.value("XftHintStyle", "hintslight").toString(); - - const QString datas = QString("Xft.dpi: %1\n" - "Xcursor.theme: %2\n" - "Xcursor.size: %3\n" - "Xft.antialias: %4\n" - "Xft.hintstyle: %5\n" - "Xft.rgba: rgb") - .arg(fontDpi) - .arg(cursorTheme) - .arg(cursorSize) - .arg(xftAntialias) - .arg(xftHintStyle); - - QProcess p; - p.start(QStringLiteral("xrdb"), {QStringLiteral("-quiet"), QStringLiteral("-merge"), QStringLiteral("-nocpp")}); - p.setProcessChannelMode(QProcess::ForwardedChannels); - p.write(datas.toLatin1()); - p.closeWriteChannel(); - p.waitForFinished(-1); - - // For cutefish-wine - qputenv("CUTEFISH_FONT_DPI", QByteArray::number(fontDpi)); - - // Init cursor - runSync("cupdatecursor", {cursorTheme, QString::number(cursorSize)}); - // qputenv("XCURSOR_THEME", cursorTheme.toLatin1()); - // qputenv("XCURSOR_SIZE", QByteArray::number(cursorSize * scaleFactor)); -} - -void Application::initKWinConfig() -{ - QSettings settings(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/kwinrc", - QSettings::IniFormat); - - settings.beginGroup("Effect-Blur"); - settings.setValue("BlurStrength", 10); - settings.setValue("NoiseStrength", 0); - settings.endGroup(); - - settings.beginGroup("Windows"); - settings.setValue("FocusStealingPreventionLevel", 0); - settings.setValue("HideUtilityWindowsForInactive", false); - settings.setValue("BorderlessMaximizedWindows", false); - settings.setValue("Placement", "Centered"); - settings.endGroup(); - - settings.beginGroup("org.kde.kdecoration2"); - settings.setValue("BorderSize", "Normal"); - settings.setValue("ButtonsOnLeft", ""); - settings.setValue("ButtonsOnRight", "HIAX"); - // The Cutefish decoration was written for the old KDecoration2 API and - // is not available on current KWin installations. Keeping this stale - // value makes KWin try to load a plugin that may no longer exist and can - // leave the session without a usable window manager. Let KWin select - // the system default decoration instead (normally Breeze). - if (settings.value("library").toString() == "org.cutefish.decoration") - settings.remove("library"); - settings.setValue("theme", ""); - settings.endGroup(); -} - bool Application::syncDBusEnvironment() { int exitCode = 0; diff --git a/session/application.h b/session/application.h index 3a119b8..afbf66c 100644 --- a/session/application.h +++ b/session/application.h @@ -33,9 +33,6 @@ class Application : public QApplication public: explicit Application(int &argc, char **argv); - bool wayland() const; - bool startWindowManager() const; - public slots: void logout() { m_processManager->logout(); @@ -70,8 +67,6 @@ private: void initEnvironments(); void initLanguage(); void initScreenScaleFactors(); - void initXResource(); - void initKWinConfig(); bool syncDBusEnvironment(); void importSystemdEnvrionment(); void createConfigDirectory(); @@ -83,8 +78,6 @@ private: NetworkProxyManager *m_networkProxyManager; Power m_power; - bool m_wayland; - bool m_startWindowManager; }; #endif // APPLICATION_H diff --git a/session/cutefish-kwin-wayland-session b/session/cutefish-kwin-wayland-session index 5c46efd..6ea0df0 100644 --- a/session/cutefish-kwin-wayland-session +++ b/session/cutefish-kwin-wayland-session @@ -1,3 +1,3 @@ #!/bin/sh -exec /usr/bin/cutefish-session --wayland --no-wm "$@" +exec /usr/bin/cutefish-session "$@" diff --git a/session/cutefish-wayland-session b/session/cutefish-wayland-session index 10911d5..2706f25 100755 --- a/session/cutefish-wayland-session +++ b/session/cutefish-wayland-session @@ -14,4 +14,4 @@ export XDG_CURRENT_DESKTOP=Cutefish export XDG_SESSION_DESKTOP=Cutefish export DESKTOP_SESSION=Cutefish -exec /usr/bin/kwin_wayland --xwayland --exit-with-session /usr/bin/cutefish-kwin-wayland-session "$@" +exec /usr/bin/kwin_wayland --exit-with-session /usr/bin/cutefish-kwin-wayland-session "$@" diff --git a/session/cutefish-xsession.desktop b/session/cutefish-xsession.desktop deleted file mode 100644 index 9086f14..0000000 --- a/session/cutefish-xsession.desktop +++ /dev/null @@ -1,7 +0,0 @@ -[Desktop Entry] -Type=Application -Exec=cutefish-session -TryExec=cutefish-session -Name=Cutefish Desktop -Keywords=session -Comment=session diff --git a/session/main.cpp b/session/main.cpp index b8394e3..ba787be 100644 --- a/session/main.cpp +++ b/session/main.cpp @@ -22,7 +22,6 @@ int main(int argc, char *argv[]) { - // putenv((char *)"SESSION_MANAGER="); QQuickWindow::setDefaultAlphaBuffer(true); diff --git a/session/processmanager.cpp b/session/processmanager.cpp index e4124c1..caf37b2 100644 --- a/session/processmanager.cpp +++ b/session/processmanager.cpp @@ -30,27 +30,17 @@ #include #include #include -#include - #include #include -#include -#include - ProcessManager::ProcessManager(Application *app, QObject *parent) : QObject(parent) , m_app(app) - , m_wmStarted(false) - , m_waitLoop(nullptr) { - qApp->installNativeEventFilter(this); } ProcessManager::~ProcessManager() { - qApp->removeNativeEventFilter(this); - QMapIterator i(m_systemProcess); while (i.hasNext()) { i.next(); @@ -62,29 +52,13 @@ ProcessManager::~ProcessManager() void ProcessManager::start() { - if (m_app->startWindowManager()) - startWindowManager(); - // The settings daemon owns the Cutefish settings D-Bus service and - // starts the desktop components after that service is ready. This is - // required for both X11 and Wayland sessions. + // starts the desktop components after that service is ready. startDaemonProcess(); } void ProcessManager::logout() { - if (!m_app->wayland()) { - QDBusInterface kwinIface("org.kde.KWin", - "/Session", - "org.kde.KWin.Session", - QDBusConnection::sessionBus()); - - if (kwinIface.isValid()) { - kwinIface.call("aboutToSaveSession", "cutefish"); - kwinIface.call("setState", uint(1)); // Quitting - } - } - // Close what we started ourselves, the window manager last since // everything else is drawn on top of it. stopProcesses(m_autoStartProcess); @@ -113,28 +87,6 @@ void ProcessManager::stopProcesses(QMap &processes) } } -void ProcessManager::startWindowManager() -{ - if (m_app->wayland()) { - qInfo() << "Using the existing Wayland compositor."; - return; - } - - QProcess *wmProcess = new QProcess; - m_systemProcess.insert("kwin", wmProcess); - - wmProcess->start("kwin_x11", QStringList()); - - if (!m_app->wayland()) { - QEventLoop waitLoop; - m_waitLoop = &waitLoop; - // add a timeout to avoid infinite blocking if a WM fail to execute. - QTimer::singleShot(30 * 1000, &waitLoop, SLOT(quit())); - waitLoop.exec(); - m_waitLoop = nullptr; - } -} - void ProcessManager::startDesktopProcess() { // When the cutefish-settings-daemon theme module is loaded, start the desktop. @@ -165,11 +117,9 @@ void ProcessManager::startDesktopProcess() process->setProcessChannelMode(QProcess::ForwardedChannels); process->setProgram(pair.first); process->setArguments(pair.second); - if (m_app->wayland()) { - QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); - environment.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("wayland")); - process->setProcessEnvironment(environment); - } + QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); + environment.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("wayland")); + process->setProcessEnvironment(environment); process->start(); process->waitForStarted(); @@ -196,12 +146,6 @@ void ProcessManager::startDaemonProcess() // the desktop components once the service is available. list << qMakePair(QString("cutefish-settings-daemon"), QStringList()); - if (!m_app->wayland()) { - list << qMakePair(QString("cutefish-xembedsniproxy"), QStringList()); - list << qMakePair(QString("cutefish-gmenuproxy"), QStringList()); - list << qMakePair(QString("chotkeys"), QStringList()); - } - for (QPair pair : list) { QProcess *process = new QProcess; process->setProcessChannelMode(QProcess::ForwardedChannels); @@ -242,19 +186,7 @@ void ProcessManager::loadAutoStartProcess() const QString execValue = desktop.value("Exec").toString(); - // 避免冲突 - if (execValue.contains("gmenudbusmenuproxy")) - continue; - - // These helpers are X11-only and are deliberately replaced by - // Wayland integration or omitted from the Wayland session. Do - // not let a legacy autostart entry bring them back after - // startDaemonProcess() skipped them. - if (m_app->wayland() - && (execValue.contains("cutefish-settings-daemon") - || execValue.contains("cutefish-xembedsniproxy") - || execValue.contains("cutefish-gmenuproxy") - || execValue.contains("chotkeys"))) + if (execValue.contains("cutefish-settings-daemon")) continue; if (!execValue.isEmpty()) { @@ -266,11 +198,9 @@ void ProcessManager::loadAutoStartProcess() for (const QString &exec : execList) { QProcess *process = new QProcess; process->setProgram(exec); - if (m_app->wayland()) { - QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); - environment.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("wayland")); - process->setProcessEnvironment(environment); - } + QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); + environment.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("wayland")); + process->setProcessEnvironment(environment); process->start(); process->waitForStarted(); @@ -281,27 +211,3 @@ void ProcessManager::loadAutoStartProcess() } } } - -bool ProcessManager::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) -{ - if (!KWindowSystem::isPlatformX11()) - return false; - - if (eventType != "xcb_generic_event_t") // We only want to handle XCB events - return false; - - // ref: lxqt session - if (!m_wmStarted && m_waitLoop) { - // all window managers must set their name according to the spec - if (!QString::fromUtf8(NETRootInfo(qGuiApp->nativeInterface()->connection(), NET::SupportingWMCheck).wmName()).isEmpty()) { - qDebug() << "Window manager started"; - m_wmStarted = true; - if (m_waitLoop && m_waitLoop->isRunning()) - m_waitLoop->exit(); - - qApp->removeNativeEventFilter(this); - } - } - - return false; -} diff --git a/session/processmanager.h b/session/processmanager.h index 0f23ba0..03de2a5 100644 --- a/session/processmanager.h +++ b/session/processmanager.h @@ -20,14 +20,13 @@ #ifndef PROCESSMANAGER_H #define PROCESSMANAGER_H -#include #include #include #include #include class Application; -class ProcessManager : public QObject, public QAbstractNativeEventFilter +class ProcessManager : public QObject { Q_OBJECT @@ -38,13 +37,10 @@ public: void start(); void logout(); - void startWindowManager(); void startDesktopProcess(); void startDaemonProcess(); void loadAutoStartProcess(); - bool nativeEventFilter(const QByteArray & eventType, void * message, qintptr * result) override; - private: void stopProcesses(QMap &processes); @@ -53,8 +49,6 @@ private: QMap m_systemProcess; QMap m_autoStartProcess; - bool m_wmStarted; - QEventLoop *m_waitLoop; }; #endif // PROCESSMANAGER_H diff --git a/settings-daemon/CMakeLists.txt b/settings-daemon/CMakeLists.txt index e879e3d..103090f 100644 --- a/settings-daemon/CMakeLists.txt +++ b/settings-daemon/CMakeLists.txt @@ -1,14 +1,6 @@ project(cutefish-settings-daemon) set(TARGET cutefish-settings-daemon) -find_package(X11 REQUIRED) -find_package(X11_XCB REQUIRED) -find_package(XCB REQUIRED COMPONENTS XCB RECORD) - -pkg_check_modules(XORGLIBINPUT xorg-libinput IMPORTED_TARGET) -pkg_check_modules(XORGSERVER xorg-server IMPORTED_TARGET) -pkg_check_modules(SYNAPTICS xorg-synaptics IMPORTED_TARGET GLOBAL) - file (GLOB_RECURSE SRCS "*.cpp" "*.h" @@ -27,8 +19,6 @@ file (GLOB_RECURSE SRCS "mouse/*.cpp" "touchpad/*.h" "touchpad/*.cpp" - "touchpad/x11/*.h" - "touchpad/x11/*.cpp" ) set(SOURCES ${SRCS}) @@ -66,15 +56,6 @@ target_link_libraries(${TARGET} Qt6::Widgets Qt6::DBus Qt6::Xml - ${X11_LIBRARIES} - X11::X11 - X11::Xi - X11::XCB - XCB::XCB - XCB::RECORD - PkgConfig::XORGLIBINPUT - PkgConfig::XORGSERVER - PkgConfig::SYNAPTICS ) file(GLOB TS_FILES translations/*.ts) diff --git a/settings-daemon/application.cpp b/settings-daemon/application.cpp index ef84eba..a10c840 100644 --- a/settings-daemon/application.cpp +++ b/settings-daemon/application.cpp @@ -42,31 +42,16 @@ Application::Application(int &argc, char **argv) , m_brightnessManager(new BrightnessManager(this)) , m_upowerManager(new UPowerManager(this)) , m_language(Language::self()) - , m_mouse(nullptr) - , m_touchpad(nullptr) + , m_mouse(new Mouse(this)) + , m_touchpad(new TouchpadManager(this)) , m_defaultApps(new DefaultApplications) -// , m_kwinTimer(new QTimer(this)) { - // Mouse and touchpad managers use the X11/XInput backend. Constructing - // them on a Wayland Qt platform dereferences a missing QX11 interface - // and makes the settings daemon exit before it can register its D-Bus - // service. - if (QGuiApplication::platformName() == QStringLiteral("xcb")) { - m_mouse = new Mouse(this); - m_touchpad = new TouchpadManager(this); - } - initTrash(); new DBusAdaptor(this); // connect to D-Bus and register as an object: QDBusConnection::sessionBus().registerService(QStringLiteral("com.cutefish.Settings")); -// m_kwinTimer->setSingleShot(false); -// m_kwinTimer->setInterval(50); -// connect(m_kwinTimer, &QTimer::timeout, this, &Application::initKWin); -// m_kwinTimer->start(); - // Translations QLocale locale; QString qmFilePath = QString("%1/%2.qm").arg("/usr/share/cutefish-settings-daemon/translations/").arg(locale.name()); @@ -121,28 +106,3 @@ void Application::initTrash() ::rmdir(trashDir); } } - -//void Application::initKWin() -//{ -// QDBusInterface effect("org.kde.KWin", "/Effects", "org.kde.kwin.Effects", -// QDBusConnection::sessionBus()); - -// if (effect.isValid() && !effect.lastError().isValid()) { -// // KWin -// effect.call("loadEffect", "kwin4_effect_dialogparent"); - -// effect.call("unloadEffect", "kwin4_effect_fadingpopups"); -// effect.call("unloadEffect", "kwin4_effect_fade"); -// effect.call("unloadEffect", "kwin4_effect_scale"); -// effect.call("unloadEffect", "kwin4_effect_grayscale"); -// effect.call("unloadEffect", "kwin4_effect_squash"); -// effect.call("unloadEffect", "kwin4_effect_translucency"); -// effect.call("unloadEffect", "magiclamp"); - -// effect.call("loadEffect", "cutefish_popups"); -// effect.call("loadEffect", "cutefish_scale"); -// effect.call("loadEffect", "cutefish_squash"); - -// m_kwinTimer->stop(); -// } -//} diff --git a/settings-daemon/application.h b/settings-daemon/application.h index 939e3f0..3c31440 100644 --- a/settings-daemon/application.h +++ b/settings-daemon/application.h @@ -41,8 +41,6 @@ public: void invokeDesktopProcess(); void initTrash(); -// void initKWin(); - private: ThemeManager *m_themeManager; BrightnessManager *m_brightnessManager; @@ -51,8 +49,6 @@ private: Mouse *m_mouse; TouchpadManager *m_touchpad; DefaultApplications *m_defaultApps; - -// QTimer *m_kwinTimer; }; #endif // APPLICATION_H diff --git a/settings-daemon/input/kwininputbackend.cpp b/settings-daemon/input/kwininputbackend.cpp new file mode 100644 index 0000000..8813459 --- /dev/null +++ b/settings-daemon/input/kwininputbackend.cpp @@ -0,0 +1,167 @@ +#include "kwininputbackend.h" + +#include +#include +#include +#include +#include +#include + +namespace +{ +constexpr auto s_service = "org.kde.KWin"; +constexpr auto s_managerPath = "/org/kde/KWin/InputDevice"; +constexpr auto s_managerInterface = "org.kde.KWin.InputDeviceManager"; +constexpr auto s_deviceInterface = "org.kde.KWin.InputDevice"; +constexpr auto s_propertiesInterface = "org.freedesktop.DBus.Properties"; +} + +KWinInputBackend::KWinInputBackend(DeviceType type, QObject *parent) + : QObject(parent) + , m_type(type) + , m_serviceWatcher(new QDBusServiceWatcher(QString::fromLatin1(s_service), + QDBusConnection::sessionBus(), + QDBusServiceWatcher::WatchForRegistration + | QDBusServiceWatcher::WatchForUnregistration, + this)) +{ + connect(m_serviceWatcher, &QDBusServiceWatcher::serviceRegistered, + this, &KWinInputBackend::refreshDevices); + connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, + this, &KWinInputBackend::refreshDevices); + + QDBusConnection::sessionBus().connect(QString::fromLatin1(s_service), + QString::fromLatin1(s_managerPath), + QString::fromLatin1(s_managerInterface), + QStringLiteral("deviceAdded"), + this, + SLOT(handleDeviceAdded(QString))); + QDBusConnection::sessionBus().connect(QString::fromLatin1(s_service), + QString::fromLatin1(s_managerPath), + QString::fromLatin1(s_managerInterface), + QStringLiteral("deviceRemoved"), + this, + SLOT(handleDeviceRemoved(QString))); + + QTimer::singleShot(0, this, &KWinInputBackend::refreshDevices); +} + +bool KWinInputBackend::available() const +{ + return !matchingDevicePaths().isEmpty(); +} + +bool KWinInputBackend::booleanProperty(const QString &name, bool fallback) const +{ + const QStringList paths = matchingDevicePaths(); + if (paths.isEmpty()) + return fallback; + + const QVariant value = readProperty(paths.constFirst(), + QString::fromLatin1(s_deviceInterface), name); + return value.isValid() ? value.toBool() : fallback; +} + +qreal KWinInputBackend::realProperty(const QString &name, qreal fallback) const +{ + const QStringList paths = matchingDevicePaths(); + if (paths.isEmpty()) + return fallback; + + const QVariant value = readProperty(paths.constFirst(), + QString::fromLatin1(s_deviceInterface), name); + return value.isValid() ? value.toReal() : fallback; +} + +void KWinInputBackend::setBooleanProperty(const QString &name, bool value) +{ + for (const QString &path : matchingDevicePaths()) + writeProperty(path, name, value); +} + +void KWinInputBackend::setRealProperty(const QString &name, qreal value) +{ + value = qBound(-1.0, value, 1.0); + for (const QString &path : matchingDevicePaths()) + writeProperty(path, name, value); +} + +void KWinInputBackend::refreshDevices() +{ + const QVariant value = readProperty(QString::fromLatin1(s_managerPath), + QString::fromLatin1(s_managerInterface), + QStringLiteral("devicesSysNames")); + const QStringList names = value.isValid() ? value.toStringList() : QStringList(); + if (names == m_deviceNames) + return; + + m_deviceNames = names; + emit devicesChanged(); +} + +void KWinInputBackend::handleDeviceAdded(const QString &sysName) +{ + if (!m_deviceNames.contains(sysName)) { + m_deviceNames.append(sysName); + emit devicesChanged(); + } +} + +void KWinInputBackend::handleDeviceRemoved(const QString &sysName) +{ + if (m_deviceNames.removeAll(sysName) > 0) + emit devicesChanged(); +} + +QStringList KWinInputBackend::matchingDevicePaths() const +{ + QStringList paths; + for (const QString &name : m_deviceNames) { + const QString path = devicePath(name); + if (matches(path)) + paths.append(path); + } + return paths; +} + +bool KWinInputBackend::matches(const QString &path) const +{ + const bool touchpad = readProperty(path, QString::fromLatin1(s_deviceInterface), + QStringLiteral("touchpad")).toBool(); + if (m_type == DeviceType::Touchpad) + return touchpad; + + const bool pointer = readProperty(path, QString::fromLatin1(s_deviceInterface), + QStringLiteral("pointer")).toBool(); + return pointer && !touchpad; +} + +QVariant KWinInputBackend::readProperty(const QString &path, const QString &interface, + const QString &name) const +{ + QDBusMessage message = QDBusMessage::createMethodCall(QString::fromLatin1(s_service), + path, + QString::fromLatin1(s_propertiesInterface), + QStringLiteral("Get")); + message << interface << name; + const QDBusReply reply = QDBusConnection::sessionBus().call(message); + return reply.isValid() ? reply.value().variant() : QVariant(); +} + +bool KWinInputBackend::writeProperty(const QString &path, const QString &name, + const QVariant &value) const +{ + QDBusMessage message = QDBusMessage::createMethodCall(QString::fromLatin1(s_service), + path, + QString::fromLatin1(s_propertiesInterface), + QStringLiteral("Set")); + message << QString::fromLatin1(s_deviceInterface) << name + << QVariant::fromValue(QDBusVariant(value)); + const QDBusMessage reply = QDBusConnection::sessionBus().call(message); + return reply.type() != QDBusMessage::ErrorMessage; +} + +QString KWinInputBackend::devicePath(const QString &sysName) +{ + return QString::fromLatin1(s_managerPath) + QLatin1Char('/') + sysName; +} diff --git a/settings-daemon/input/kwininputbackend.h b/settings-daemon/input/kwininputbackend.h new file mode 100644 index 0000000..1f79f0d --- /dev/null +++ b/settings-daemon/input/kwininputbackend.h @@ -0,0 +1,51 @@ +#ifndef KWININPUTBACKEND_H +#define KWININPUTBACKEND_H + +#include +#include +#include + +class QDBusServiceWatcher; + +class KWinInputBackend : public QObject +{ + Q_OBJECT + +public: + enum class DeviceType { + Pointer, + Touchpad, + }; + + explicit KWinInputBackend(DeviceType type, QObject *parent = nullptr); + + bool available() const; + bool booleanProperty(const QString &name, bool fallback = false) const; + qreal realProperty(const QString &name, qreal fallback = 0.0) const; + + void setBooleanProperty(const QString &name, bool value); + void setRealProperty(const QString &name, qreal value); + +signals: + void devicesChanged(); + +private slots: + void refreshDevices(); + void handleDeviceAdded(const QString &sysName); + void handleDeviceRemoved(const QString &sysName); + +private: + QStringList matchingDevicePaths() const; + bool matches(const QString &path) const; + QVariant readProperty(const QString &path, const QString &interface, + const QString &name) const; + bool writeProperty(const QString &path, const QString &name, + const QVariant &value) const; + static QString devicePath(const QString &sysName); + + DeviceType m_type; + QStringList m_deviceNames; + QDBusServiceWatcher *m_serviceWatcher; +}; + +#endif // KWININPUTBACKEND_H diff --git a/settings-daemon/mouse/com.cutefish.Mouse.xml b/settings-daemon/mouse/com.cutefish.Mouse.xml index bffd01f..e4c7f54 100644 --- a/settings-daemon/mouse/com.cutefish.Mouse.xml +++ b/settings-daemon/mouse/com.cutefish.Mouse.xml @@ -1,6 +1,9 @@ + + + @@ -12,5 +15,9 @@ + + + + diff --git a/settings-daemon/mouse/libinputsettings.cpp b/settings-daemon/mouse/libinputsettings.cpp deleted file mode 100644 index 7bfd61e..0000000 --- a/settings-daemon/mouse/libinputsettings.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Roman Gilg - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#include "libinputsettings.h" - -#include -#include - -template<> -bool LibinputSettings::load(QString key, bool defVal) -{ - QSettings settings("cutefishos", "mouse"); - return settings.value(key, defVal).toBool(); -} - -template<> -qreal LibinputSettings::load(QString key, qreal defVal) -{ - QSettings settings("cutefishos", "mouse"); - return settings.value(key, defVal).toReal(); -} - -template<> -void LibinputSettings::save(QString key, bool val) -{ - QSettings settings("cutefishos", "mouse"); - settings.setValue(key, val); - settings.sync(); -} - -template<> -void LibinputSettings::save(QString key, qreal val) -{ - QSettings settings("cutefishos", "mouse"); - settings.setValue(key, val); - settings.sync(); -} diff --git a/settings-daemon/mouse/libinputsettings.h b/settings-daemon/mouse/libinputsettings.h deleted file mode 100644 index 5941690..0000000 --- a/settings-daemon/mouse/libinputsettings.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Roman Gilg - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef LIBINPUTSETTINGS_H -#define LIBINPUTSETTINGS_H - -#include - -struct LibinputSettings { - template - T load(QString key, T defVal); - - template - void save(QString key, T val); -}; - -#endif // LIBINPUTSETTINGS_H diff --git a/settings-daemon/mouse/mousemanager.cpp b/settings-daemon/mouse/mousemanager.cpp index 6fbdf24..f55913a 100644 --- a/settings-daemon/mouse/mousemanager.cpp +++ b/settings-daemon/mouse/mousemanager.cpp @@ -1,86 +1,83 @@ -/* - * Copyright (C) 2021 CutefishOS Team. - * - * Author: Reion Wong - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - #include "mousemanager.h" #include "mouseadaptor.h" -#include +#include "input/kwininputbackend.h" + +#include Mouse::Mouse(QObject *parent) : QObject(parent) - , m_inputDummydevice(new X11LibinputDummyDevice(this, qGuiApp->nativeInterface()->display())) + , m_backend(new KWinInputBackend(KWinInputBackend::DeviceType::Pointer, this)) { - // init dbus new MouseAdaptor(this); QDBusConnection::sessionBus().registerObject(QStringLiteral("/Mouse"), this); - connect(m_inputDummydevice, &X11LibinputDummyDevice::leftHandedChanged, this, &Mouse::leftHandedChanged); - connect(m_inputDummydevice, &X11LibinputDummyDevice::pointerAccelerationProfileChanged, this, &Mouse::accelerationChanged); - connect(m_inputDummydevice, &X11LibinputDummyDevice::naturalScrollChanged, this, &Mouse::naturalScrollChanged); - connect(m_inputDummydevice, &X11LibinputDummyDevice::pointerAccelerationChanged, this, &Mouse::pointerAccelerationChanged); + connect(m_backend, &KWinInputBackend::devicesChanged, this, [this] { + emit availableChanged(); + emit leftHandedChanged(); + emit accelerationChanged(); + emit naturalScrollChanged(); + emit pointerAccelerationChanged(); + }); } -Mouse::~Mouse() +Mouse::~Mouse() = default; + +bool Mouse::available() const { - delete m_inputDummydevice; + return m_backend->available(); } bool Mouse::leftHanded() const { - return m_inputDummydevice->isLeftHanded(); + return m_backend->booleanProperty(QStringLiteral("leftHanded")); } void Mouse::setLeftHanded(bool enabled) { - m_inputDummydevice->setLeftHanded(enabled); - m_inputDummydevice->applyConfig(); + if (leftHanded() == enabled) + return; + m_backend->setBooleanProperty(QStringLiteral("leftHanded"), enabled); + emit leftHandedChanged(); } bool Mouse::acceleration() const { - return m_inputDummydevice->pointerAccelerationProfileFlat(); + return m_backend->booleanProperty(QStringLiteral("pointerAccelerationProfileFlat")); } void Mouse::setAcceleration(bool enabled) { - m_inputDummydevice->setPointerAccelerationProfileFlat(enabled); - m_inputDummydevice->applyConfig(); + if (acceleration() == enabled) + return; + m_backend->setBooleanProperty(QStringLiteral("pointerAccelerationProfileFlat"), enabled); + m_backend->setBooleanProperty(QStringLiteral("pointerAccelerationProfileAdaptive"), !enabled); + emit accelerationChanged(); } bool Mouse::naturalScroll() const { - return m_inputDummydevice->isNaturalScroll(); + return m_backend->booleanProperty(QStringLiteral("naturalScroll")); } void Mouse::setNaturalScroll(bool enabled) { - m_inputDummydevice->setNaturalScroll(enabled); - m_inputDummydevice->applyConfig(); + if (naturalScroll() == enabled) + return; + m_backend->setBooleanProperty(QStringLiteral("naturalScroll"), enabled); + emit naturalScrollChanged(); } qreal Mouse::pointerAcceleration() const { - return m_inputDummydevice->pointerAcceleration(); + return m_backend->realProperty(QStringLiteral("pointerAcceleration")); } void Mouse::setPointerAcceleration(qreal value) { - m_inputDummydevice->setPointerAcceleration(value); - m_inputDummydevice->applyConfig(); + value = qBound(-1.0, value, 1.0); + if (qFuzzyCompare(1.0 + pointerAcceleration(), 1.0 + value)) + return; + m_backend->setRealProperty(QStringLiteral("pointerAcceleration"), value); + emit pointerAccelerationChanged(); } diff --git a/settings-daemon/mouse/mousemanager.h b/settings-daemon/mouse/mousemanager.h index 1a14a60..66b8e55 100644 --- a/settings-daemon/mouse/mousemanager.h +++ b/settings-daemon/mouse/mousemanager.h @@ -21,11 +21,13 @@ #define MOUSE_H #include -#include "x11libinputdummydevice.h" + +class KWinInputBackend; class Mouse : public QObject { Q_OBJECT + Q_PROPERTY(bool available READ available NOTIFY availableChanged) Q_PROPERTY(bool leftHanded READ leftHanded WRITE setLeftHanded NOTIFY leftHandedChanged) Q_PROPERTY(bool acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged) Q_PROPERTY(bool naturalScroll READ naturalScroll WRITE setNaturalScroll NOTIFY naturalScrollChanged) @@ -33,8 +35,9 @@ class Mouse : public QObject public: explicit Mouse(QObject *parent = nullptr); - ~Mouse(); + ~Mouse() override; + bool available() const; bool leftHanded() const; void setLeftHanded(bool enabled); @@ -48,13 +51,14 @@ public: void setPointerAcceleration(qreal value); signals: + void availableChanged(); void leftHandedChanged(); void accelerationChanged(); void naturalScrollChanged(); void pointerAccelerationChanged(); private: - X11LibinputDummyDevice *m_inputDummydevice; + KWinInputBackend *m_backend; }; #endif // MOUSE_H diff --git a/settings-daemon/mouse/x11libinputdummydevice.cpp b/settings-daemon/mouse/x11libinputdummydevice.cpp deleted file mode 100644 index 6c9b44d..0000000 --- a/settings-daemon/mouse/x11libinputdummydevice.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Roman Gilg - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#include "x11libinputdummydevice.h" -#include "libinputsettings.h" -#include -#include - -#include -#include -#include - -static Atom s_touchpadAtom; - -template -static void XIForallPointerDevices(Display *dpy, const Callback &callback) -{ - int ndevices_return; - XDeviceInfo *info = XListInputDevices(dpy, &ndevices_return); - if (!info) { - return; - } - for (int i = 0; i < ndevices_return; ++i) { - XDeviceInfo *dev = info + i; - if ((dev->use == IsXPointer || dev->use == IsXExtensionPointer) && dev->type != s_touchpadAtom) { - callback(dev); - } - } - XFreeDeviceList(info); -} - -struct ScopedXDeleter { - static inline void cleanup(void *pointer) - { - if (pointer) { - XFree(pointer); - } - } -}; - -namespace -{ -template -void valueWriterPart(T val, Atom valAtom, Display *dpy) -{ - Q_UNUSED(val); - Q_UNUSED(valAtom); - Q_UNUSED(dpy); -} - -template<> -void valueWriterPart(bool val, Atom valAtom, Display *dpy) -{ - XIForallPointerDevices(dpy, [&](XDeviceInfo *info) { - int deviceid = info->id; - Status status; - Atom type_return; - int format_return; - unsigned long num_items_return; - unsigned long bytes_after_return; - - unsigned char *_data = nullptr; - // data returned is an 1 byte boolean - status = XIGetProperty(dpy, deviceid, valAtom, 0, 1, False, XA_INTEGER, &type_return, &format_return, &num_items_return, &bytes_after_return, &_data); - if (status != Success) { - return; - } - - QScopedArrayPointer data(_data); - _data = nullptr; - - if (type_return != XA_INTEGER || !data || format_return != 8) { - return; - } - - unsigned char sendVal[2] = {0}; - if (num_items_return == 1) { - sendVal[0] = val; - } else { - // Special case for acceleration profile. - const Atom accel = XInternAtom(dpy, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, True); - if (num_items_return != 2 || valAtom != accel) { - return; - } - sendVal[val] = 1; - } - - XIChangeProperty(dpy, deviceid, valAtom, XA_INTEGER, 8, XIPropModeReplace, sendVal, num_items_return); - }); -} - -template<> -void valueWriterPart(qreal val, Atom valAtom, Display *dpy) -{ - XIForallPointerDevices(dpy, [&](XDeviceInfo *info) { - int deviceid = info->id; - Status status; - Atom float_type = XInternAtom(dpy, "FLOAT", False); - Atom type_return; - int format_return; - unsigned long num_items_return; - unsigned long bytes_after_return; - - unsigned char *_data = nullptr; - // data returned is an 1 byte boolean - status = XIGetProperty(dpy, deviceid, valAtom, 0, 1, False, float_type, &type_return, &format_return, &num_items_return, &bytes_after_return, &_data); - if (status != Success) { - return; - } - - QScopedArrayPointer data(_data); - _data = nullptr; - - if (type_return != float_type || !data || format_return != 32 || num_items_return != 1) { - return; - } - - unsigned char buffer[4096]; - float *sendPtr = (float *)buffer; - *sendPtr = val; - - XIChangeProperty(dpy, deviceid, valAtom, float_type, format_return, XIPropModeReplace, buffer, 1); - }); -} -} - -X11LibinputDummyDevice::X11LibinputDummyDevice(QObject *parent, Display *dpy) - : QObject(parent) - , m_settings(new LibinputSettings()) - , m_dpy(dpy) -{ - m_leftHanded.atom = XInternAtom(dpy, LIBINPUT_PROP_LEFT_HANDED, True); - m_middleEmulation.atom = XInternAtom(dpy, LIBINPUT_PROP_MIDDLE_EMULATION_ENABLED, True); - m_naturalScroll.atom = XInternAtom(dpy, LIBINPUT_PROP_NATURAL_SCROLL, True); - m_pointerAcceleration.atom = XInternAtom(dpy, LIBINPUT_PROP_ACCEL, True); - m_pointerAccelerationProfileFlat.atom = XInternAtom(dpy, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, True); - - m_supportsDisableEvents.val = false; - m_enabled.val = true; - m_supportedButtons.val = Qt::LeftButton | Qt::MiddleButton | Qt::RightButton; - m_supportsLeftHanded.val = true; - m_supportsMiddleEmulation.val = true; - m_middleEmulationEnabledByDefault.val = false; - - m_supportsPointerAcceleration.val = true; - m_defaultPointerAcceleration.val = 0; - - m_supportsPointerAccelerationProfileAdaptive.val = true; - m_supportsPointerAccelerationProfileFlat.val = true; - - m_defaultPointerAccelerationProfileAdaptive.val = true; - m_defaultPointerAccelerationProfileFlat.val = false; - - m_supportsNaturalScroll.val = true; - m_naturalScrollEnabledByDefault.val = false; - - s_touchpadAtom = XInternAtom(m_dpy, XI_TOUCHPAD, True); - - // Init - getConfig(); - applyConfig(); -} - -X11LibinputDummyDevice::~X11LibinputDummyDevice() -{ - delete m_settings; -} - -bool X11LibinputDummyDevice::getConfig() -{ - auto reset = [this](Prop &prop, bool defVal) { - prop.reset(m_settings->load(prop.cfgName, defVal)); - }; - - reset(m_leftHanded, false); - - reset(m_middleEmulation, false); - reset(m_naturalScroll, false); - reset(m_pointerAccelerationProfileFlat, false); - - m_pointerAccelerationProfileAdaptive.reset(!m_settings->load(m_pointerAccelerationProfileFlat.cfgName, false)); - m_pointerAcceleration.reset(m_settings->load(m_pointerAcceleration.cfgName, 0.)); - - emit leftHandedChanged(); - emit naturalScrollChanged(); - emit pointerAccelerationProfileChanged(); - emit pointerAccelerationChanged(); - - return true; -} - -bool X11LibinputDummyDevice::getDefaultConfig() -{ - m_leftHanded.set(false); - - m_pointerAcceleration.set(m_defaultPointerAcceleration); - m_pointerAccelerationProfileFlat.set(m_defaultPointerAccelerationProfileFlat); - m_pointerAccelerationProfileAdaptive.set(m_defaultPointerAccelerationProfileAdaptive); - - m_middleEmulation.set(m_middleEmulationEnabledByDefault); - m_naturalScroll.set(m_naturalScrollEnabledByDefault); - - return true; -} - -bool X11LibinputDummyDevice::applyConfig() -{ - valueWriter(m_leftHanded); - valueWriter(m_middleEmulation); - valueWriter(m_naturalScroll); - valueWriter(m_pointerAcceleration); - valueWriter(m_pointerAccelerationProfileFlat); - - return true; -} - -template -bool X11LibinputDummyDevice::valueWriter(Prop &prop) -{ - // Check atom availability first. - if (prop.atom == None) { - return false; - } - - if (prop.val != prop.old) { - m_settings->save(prop.cfgName, prop.val); - } - - valueWriterPart(prop.val, prop.atom, m_dpy); - - prop.old = prop.val; - - return true; -} - -bool X11LibinputDummyDevice::isChangedConfig() const -{ - return m_leftHanded.changed() || m_pointerAcceleration.changed() || m_pointerAccelerationProfileFlat.changed() - || m_pointerAccelerationProfileAdaptive.changed() || m_middleEmulation.changed() || m_naturalScroll.changed(); -} diff --git a/settings-daemon/mouse/x11libinputdummydevice.h b/settings-daemon/mouse/x11libinputdummydevice.h deleted file mode 100644 index 1356367..0000000 --- a/settings-daemon/mouse/x11libinputdummydevice.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - SPDX-FileCopyrightText: 2018 Roman Gilg - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef X11LIBINPUTDUMMYDEVICE_H -#define X11LIBINPUTDUMMYDEVICE_H - -#include -#include - -#include -#include - -struct LibinputSettings; - -class X11LibinputDummyDevice : public QObject -{ - Q_OBJECT - - // - // general - Q_PROPERTY(QString name READ name CONSTANT) - Q_PROPERTY(bool supportsDisableEvents READ supportsDisableEvents CONSTANT) - Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) - - // - // advanced - Q_PROPERTY(Qt::MouseButtons supportedButtons READ supportedButtons CONSTANT) - - Q_PROPERTY(bool supportsLeftHanded READ supportsLeftHanded CONSTANT) - Q_PROPERTY(bool leftHandedEnabledByDefault READ leftHandedEnabledByDefault CONSTANT) - Q_PROPERTY(bool leftHanded READ isLeftHanded WRITE setLeftHanded NOTIFY leftHandedChanged) - - Q_PROPERTY(bool supportsMiddleEmulation READ supportsMiddleEmulation CONSTANT) - Q_PROPERTY(bool middleEmulationEnabledByDefault READ middleEmulationEnabledByDefault CONSTANT) - Q_PROPERTY(bool middleEmulation READ isMiddleEmulation WRITE setMiddleEmulation NOTIFY middleEmulationChanged) - - // - // acceleration speed and profile - Q_PROPERTY(bool supportsPointerAcceleration READ supportsPointerAcceleration CONSTANT) - Q_PROPERTY(qreal pointerAcceleration READ pointerAcceleration WRITE setPointerAcceleration NOTIFY pointerAccelerationChanged) - - Q_PROPERTY(bool supportsPointerAccelerationProfileFlat READ supportsPointerAccelerationProfileFlat CONSTANT) - Q_PROPERTY(bool defaultPointerAccelerationProfileFlat READ defaultPointerAccelerationProfileFlat CONSTANT) - Q_PROPERTY(bool pointerAccelerationProfileFlat READ pointerAccelerationProfileFlat WRITE setPointerAccelerationProfileFlat NOTIFY - pointerAccelerationProfileChanged) - - Q_PROPERTY(bool supportsPointerAccelerationProfileAdaptive READ supportsPointerAccelerationProfileAdaptive CONSTANT) - Q_PROPERTY(bool defaultPointerAccelerationProfileAdaptive READ defaultPointerAccelerationProfileAdaptive CONSTANT) - Q_PROPERTY(bool pointerAccelerationProfileAdaptive READ pointerAccelerationProfileAdaptive WRITE setPointerAccelerationProfileAdaptive NOTIFY - pointerAccelerationProfileChanged) - - // - // scrolling - Q_PROPERTY(bool supportsNaturalScroll READ supportsNaturalScroll CONSTANT) - Q_PROPERTY(bool naturalScrollEnabledByDefault READ naturalScrollEnabledByDefault CONSTANT) - Q_PROPERTY(bool naturalScroll READ isNaturalScroll WRITE setNaturalScroll NOTIFY naturalScrollChanged) - -public: - X11LibinputDummyDevice(QObject *parent, Display *dpy); - ~X11LibinputDummyDevice() override; - - bool getConfig(); - bool getDefaultConfig(); - bool applyConfig(); - bool isChangedConfig() const; - - // - // general - QString name() const - { - return m_name.val; - } - QString sysName() const - { - return m_sysName.val; - } - bool supportsDisableEvents() const - { - return m_supportsDisableEvents.val; - } - void setEnabled(bool enabled) - { - m_enabled.set(enabled); - } - bool isEnabled() const - { - return m_enabled.val; - } - Qt::MouseButtons supportedButtons() const - { - return m_supportedButtons.val; - } - - // - // advanced - bool supportsLeftHanded() const - { - return m_supportsLeftHanded.val; - } - bool leftHandedEnabledByDefault() const - { - return m_leftHandedEnabledByDefault.val; - } - bool isLeftHanded() const - { - return m_leftHanded.val; - } - void setLeftHanded(bool set) - { - m_leftHanded.set(set); - } - - bool supportsMiddleEmulation() const - { - return m_supportsMiddleEmulation.val; - } - bool middleEmulationEnabledByDefault() const - { - return m_middleEmulationEnabledByDefault.val; - } - bool isMiddleEmulation() const - { - return m_middleEmulation.val; - } - void setMiddleEmulation(bool set) - { - m_middleEmulation.set(set); - } - - // - // acceleration speed and profile - bool supportsPointerAcceleration() const - { - return m_supportsPointerAcceleration.val; - } - qreal pointerAcceleration() const - { - return m_pointerAcceleration.val; - } - void setPointerAcceleration(qreal acceleration) - { - m_pointerAcceleration.set(acceleration); - } - - bool supportsPointerAccelerationProfileFlat() const - { - return m_supportsPointerAccelerationProfileFlat.val; - } - bool defaultPointerAccelerationProfileFlat() const - { - return m_defaultPointerAccelerationProfileFlat.val; - } - bool pointerAccelerationProfileFlat() const - { - return m_pointerAccelerationProfileFlat.val; - } - void setPointerAccelerationProfileFlat(bool set) - { - m_pointerAccelerationProfileFlat.set(set); - } - - bool supportsPointerAccelerationProfileAdaptive() const - { - return m_supportsPointerAccelerationProfileAdaptive.val; - } - bool defaultPointerAccelerationProfileAdaptive() const - { - return m_defaultPointerAccelerationProfileAdaptive.val; - } - bool pointerAccelerationProfileAdaptive() const - { - return m_pointerAccelerationProfileAdaptive.val; - } - void setPointerAccelerationProfileAdaptive(bool set) - { - m_pointerAccelerationProfileAdaptive.set(set); - } - - // - // scrolling - bool supportsNaturalScroll() const - { - return m_supportsNaturalScroll.val; - } - bool naturalScrollEnabledByDefault() const - { - return m_naturalScrollEnabledByDefault.val; - } - bool isNaturalScroll() const - { - return m_naturalScroll.val; - } - void setNaturalScroll(bool set) - { - m_naturalScroll.set(set); - } - -Q_SIGNALS: - void leftHandedChanged(); - void pointerAccelerationChanged(); - void pointerAccelerationProfileChanged(); - void enabledChanged(); - void middleEmulationChanged(); - void naturalScrollChanged(); - -private: - template - struct Prop { - explicit Prop(const QString &_name, const QString &_cfgName = "") - : name(_name) - , cfgName(_cfgName) - { - } - - void set(T newVal) - { - if (avail && val != newVal) { - val = newVal; - } - } - void set(const Prop &p) - { - if (avail && val != p.val) { - val = p.val; - } - } - bool changed() const - { - return avail && (old != val); - } - - void reset(T newVal) - { - val = newVal; - old = newVal; - } - - QString name; - QString cfgName; - - bool avail = true; - T old; - T val; - - Atom atom; - }; - - template - bool valueWriter(Prop &prop); - - // - // general - Prop m_name = Prop("name"); - Prop m_sysName = Prop("sysName"); - Prop m_supportsDisableEvents = Prop("supportsDisableEvents"); - Prop m_enabled = Prop("enabled"); - - // - // advanced - Prop m_supportedButtons = Prop("supportedButtons"); - - Prop m_supportsLeftHanded = Prop("supportsLeftHanded"); - Prop m_leftHandedEnabledByDefault = Prop("leftHandedEnabledByDefault"); - Prop m_leftHanded = Prop("leftHanded", "XLbInptLeftHanded"); - - Prop m_supportsMiddleEmulation = Prop("supportsMiddleEmulation"); - Prop m_middleEmulationEnabledByDefault = Prop("middleEmulationEnabledByDefault"); - Prop m_middleEmulation = Prop("middleEmulation", "XLbInptMiddleEmulation"); - - // - // acceleration speed and profile - Prop m_supportsPointerAcceleration = Prop("supportsPointerAcceleration"); - Prop m_defaultPointerAcceleration = Prop("defaultPointerAcceleration"); - Prop m_pointerAcceleration = Prop("pointerAcceleration", "XLbInptPointerAcceleration"); - - Prop m_supportsPointerAccelerationProfileFlat = Prop("supportsPointerAccelerationProfileFlat"); - Prop m_defaultPointerAccelerationProfileFlat = Prop("defaultPointerAccelerationProfileFlat"); - Prop m_pointerAccelerationProfileFlat = Prop("pointerAccelerationProfileFlat", "XLbInptAccelProfileFlat"); - - Prop m_supportsPointerAccelerationProfileAdaptive = Prop("supportsPointerAccelerationProfileAdaptive"); - Prop m_defaultPointerAccelerationProfileAdaptive = Prop("defaultPointerAccelerationProfileAdaptive"); - Prop m_pointerAccelerationProfileAdaptive = Prop("pointerAccelerationProfileAdaptive"); - - // - // scrolling - Prop m_supportsNaturalScroll = Prop("supportsNaturalScroll"); - Prop m_naturalScrollEnabledByDefault = Prop("naturalScrollEnabledByDefault"); - Prop m_naturalScroll = Prop("naturalScroll", "XLbInptNaturalScroll"); - - LibinputSettings *m_settings; - Display *m_dpy = nullptr; -}; - -#endif // X11LIBINPUTDUMMYDEVICE_H diff --git a/settings-daemon/theme/com.cutefish.Theme.xml b/settings-daemon/theme/com.cutefish.Theme.xml index b6b6eb4..17ba141 100644 --- a/settings-daemon/theme/com.cutefish.Theme.xml +++ b/settings-daemon/theme/com.cutefish.Theme.xml @@ -44,7 +44,7 @@ - + diff --git a/settings-daemon/theme/thememanager.cpp b/settings-daemon/theme/thememanager.cpp index 71c2bc1..ab30480 100644 --- a/settings-daemon/theme/thememanager.cpp +++ b/settings-daemon/theme/thememanager.cpp @@ -78,8 +78,8 @@ ThemeManager::ThemeManager(QObject *parent) m_cursorSize = m_settings->value("CursorSize", 24).toInt(); m_iconTheme = m_settings->value("IconTheme", "Crule").toString(); - // Start the DE and need to update the settings again. - updateGtk3Config(); + // Synchronize toolkit and compositor cursor settings at session startup. + applyCursorSettings(); // Init fonts. if (!m_settings->contains(s_systemFixedFontName)) { @@ -186,8 +186,7 @@ void ThemeManager::setCursorTheme(const QString &theme) if (m_cursorTheme != theme) { m_cursorTheme = theme; m_settings->setValue("CursorTheme", m_cursorTheme); - applyXResources(); - applyCursor(); + applyCursorSettings(); emit cursorThemeChanged(); } } @@ -202,8 +201,7 @@ void ThemeManager::setCursorSize(int size) if (m_cursorSize != size) { m_cursorSize = size; m_settings->setValue("CursorSize", m_cursorSize); - applyXResources(); - applyCursor(); + applyCursorSettings(); emit cursorSizeChanged(); } } @@ -258,17 +256,16 @@ qreal ThemeManager::devicePixelRatio() void ThemeManager::setDevicePixelRatio(qreal ratio) { - int fontDpi = qRound(ratio * 96.0); + ratio = qBound(1.0, ratio, 4.0); m_settings->setValue(s_devicePixelRatio, ratio); - m_settings->setValue("forceFontDPI", fontDpi); m_settings->sync(); - applyXResources(); + updateGtk3Config(); + applyCursorSettings(); - // SDDM QProcess p; p.setProgram("pkexec"); p.setArguments(QStringList() << "cutefish-sddm-helper" - << "--dpi" << QString::number(fontDpi)); + << "--scale" << QString::number(ratio)); p.start(); p.waitForFinished(-1); @@ -344,6 +341,8 @@ void ThemeManager::updateGtk3Config() settings.setValue("gtk-application-prefer-dark-theme", isDarkMode()); // icon theme settings.setValue("gtk-icon-theme-name", m_iconTheme); + settings.setValue("gtk-cursor-theme-name", m_cursorTheme); + settings.setValue("gtk-cursor-theme-size", qRound(m_cursorSize * devicePixelRatio())); // other settings.setValue("gtk-enable-animations", true); // theme @@ -351,48 +350,40 @@ void ThemeManager::updateGtk3Config() settings.sync(); } -void ThemeManager::applyXResources() +void ThemeManager::applyFontSettings() { m_settings->sync(); - - qreal scaleFactor = this->devicePixelRatio(); - int fontDpi = 96 * scaleFactor; - - int xftAntialias = m_settings->value("XftAntialias", 1).toBool(); - QString xftHintStyle = m_settings->value("XftHintStyle", "hintfull").toString(); - - const QString datas = QString("Xft.dpi: %1\n" - "Xcursor.theme: %2\n" - "Xcursor.size: %3\n" - "Xft.antialias: %4\n" - "Xft.hintstyle: %5") - .arg(fontDpi) - .arg(m_cursorTheme) - .arg(m_cursorSize * scaleFactor) - .arg(xftAntialias) - .arg(xftHintStyle); - - QProcess p; - p.start(QStringLiteral("xrdb"), {QStringLiteral("-quiet"), QStringLiteral("-merge"), QStringLiteral("-nocpp")}); - p.setProcessChannelMode(QProcess::ForwardedChannels); - p.write(datas.toLatin1()); - p.closeWriteChannel(); - p.waitForFinished(-1); + updateFontConfig(); + updateGtk3Config(); } -void ThemeManager::applyCursor() +void ThemeManager::applyCursorSettings() { - QProcess p; - p.start("cupdatecursor", QStringList() << cursorTheme() << QString::number(cursorSize() * devicePixelRatio())); - p.waitForFinished(-1); + m_settings->sync(); + + QSettings inputSettings(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + + QStringLiteral("/kcminputrc"), + QSettings::IniFormat); + inputSettings.beginGroup(QStringLiteral("Mouse")); + inputSettings.setValue(QStringLiteral("cursorTheme"), cursorTheme()); + inputSettings.setValue(QStringLiteral("cursorSize"), + qRound(cursorSize() * devicePixelRatio())); + inputSettings.endGroup(); + inputSettings.sync(); + + updateGtk3Config(); QDBusMessage message = QDBusMessage::createSignal("/KGlobalSettings", "org.kde.KGlobalSettings", "notifyChange"); - // ChangeCursor message << 5; message << 0; QDBusConnection::sessionBus().send(message); + + QDBusInterface kwin(QStringLiteral("org.kde.KWin"), QStringLiteral("/KWin"), + QStringLiteral("org.kde.KWin"), QDBusConnection::sessionBus()); + if (kwin.isValid()) + kwin.asyncCall(QStringLiteral("reconfigure")); } void ThemeManager::updateFontConfig() @@ -412,8 +403,8 @@ void ThemeManager::updateFontConfig() const QString familyFallback = familyFont; QSettings settings(QSettings::UserScope, "cutefishos", "theme"); - bool hinting = settings.value("XftAntialias", 1).toBool(); - QString hintStyle = settings.value("XftHintStyle", "hintslight").toString(); + bool hinting = settings.value("FontAntialias", true).toBool(); + QString hintStyle = settings.value("FontHintStyle", "hintslight").toString(); QString content = QString("" "" diff --git a/settings-daemon/theme/thememanager.h b/settings-daemon/theme/thememanager.h index f5176bc..fb0b822 100644 --- a/settings-daemon/theme/thememanager.h +++ b/settings-daemon/theme/thememanager.h @@ -86,8 +86,8 @@ public: void updateGtk2Config(); void updateGtk3Config(); - void applyXResources(); - void applyCursor(); + void applyFontSettings(); + void applyCursorSettings(); QString iconTheme() const; void setIconTheme(const QString &iconTheme); diff --git a/settings-daemon/touchpad/com.cutefish.Touchpad.xml b/settings-daemon/touchpad/com.cutefish.Touchpad.xml index ab93842..fe4ffab 100644 --- a/settings-daemon/touchpad/com.cutefish.Touchpad.xml +++ b/settings-daemon/touchpad/com.cutefish.Touchpad.xml @@ -7,6 +7,12 @@ + + + + + + diff --git a/settings-daemon/touchpad/libinputcommon.cpp b/settings-daemon/touchpad/libinputcommon.cpp deleted file mode 100644 index 2d0a92d..0000000 --- a/settings-daemon/touchpad/libinputcommon.cpp +++ /dev/null @@ -1,9 +0,0 @@ -/* - SPDX-FileCopyrightText: 2019 Atul Bisht - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#include "libinputcommon.h" - -#include "moc_libinputcommon.cpp" diff --git a/settings-daemon/touchpad/libinputcommon.h b/settings-daemon/touchpad/libinputcommon.h deleted file mode 100644 index 7d18def..0000000 --- a/settings-daemon/touchpad/libinputcommon.h +++ /dev/null @@ -1,566 +0,0 @@ -/* - SPDX-FileCopyrightText: 2017 Roman Gilg - SPDX-FileCopyrightText: 2019 Atul Bisht - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef LIBINPUTCOMMON_H -#define LIBINPUTCOMMON_H - -#include -#include - -namespace -{ -template -inline T valueLoaderPart(QVariant const &reply) -{ - Q_UNUSED(reply); - return T(); -} - -template<> -inline bool valueLoaderPart(QVariant const &reply) -{ - return reply.toBool(); -} - -template<> -inline int valueLoaderPart(QVariant const &reply) -{ - return reply.toInt(); -} - -template<> -inline quint32 valueLoaderPart(QVariant const &reply) -{ - return reply.toInt(); -} - -template<> -inline qreal valueLoaderPart(QVariant const &reply) -{ - return reply.toReal(); -} - -template<> -inline QString valueLoaderPart(QVariant const &reply) -{ - return reply.toString(); -} - -template<> -inline Qt::MouseButtons valueLoaderPart(QVariant const &reply) -{ - return static_cast(reply.toInt()); -} -} - -class LibinputCommon : public QObject -{ - Q_OBJECT - - // - // general - Q_PROPERTY(QString name READ name CONSTANT) - Q_PROPERTY(bool supportsDisableEvents READ supportsDisableEvents CONSTANT) - Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) - - // - // advanced - Q_PROPERTY(Qt::MouseButtons supportedButtons READ supportedButtons CONSTANT) - - Q_PROPERTY(bool supportsLeftHanded READ supportsLeftHanded CONSTANT) - Q_PROPERTY(bool leftHandedEnabledByDefault READ leftHandedEnabledByDefault CONSTANT) - Q_PROPERTY(bool leftHanded READ isLeftHanded WRITE setLeftHanded NOTIFY leftHandedChanged) - - Q_PROPERTY(bool supportsDisableEventsOnExternalMouse READ supportsDisableEventsOnExternalMouse CONSTANT) - - Q_PROPERTY(bool supportsDisableWhileTyping READ supportsDisableWhileTyping CONSTANT) - Q_PROPERTY(bool disableWhileTypingEnabledByDefault READ disableWhileTypingEnabledByDefault CONSTANT) - Q_PROPERTY(bool disableWhileTyping READ isDisableWhileTyping WRITE setDisableWhileTyping NOTIFY disableWhileTypingChanged) - - Q_PROPERTY(bool supportsMiddleEmulation READ supportsMiddleEmulation CONSTANT) - Q_PROPERTY(bool middleEmulationEnabledByDefault READ middleEmulationEnabledByDefault CONSTANT) - Q_PROPERTY(bool middleEmulation READ isMiddleEmulation WRITE setMiddleEmulation NOTIFY middleEmulationChanged) - - // - // acceleration speed and profile - Q_PROPERTY(bool supportsPointerAcceleration READ supportsPointerAcceleration CONSTANT) - Q_PROPERTY(qreal pointerAcceleration READ pointerAcceleration WRITE setPointerAcceleration NOTIFY pointerAccelerationChanged) - - Q_PROPERTY(bool supportsPointerAccelerationProfileFlat READ supportsPointerAccelerationProfileFlat CONSTANT) - Q_PROPERTY(bool defaultPointerAccelerationProfileFlat READ defaultPointerAccelerationProfileFlat CONSTANT) - Q_PROPERTY(bool pointerAccelerationProfileFlat READ pointerAccelerationProfileFlat WRITE setPointerAccelerationProfileFlat NOTIFY - pointerAccelerationProfileChanged) - - Q_PROPERTY(bool supportsPointerAccelerationProfileAdaptive READ supportsPointerAccelerationProfileAdaptive CONSTANT) - Q_PROPERTY(bool defaultPointerAccelerationProfileAdaptive READ defaultPointerAccelerationProfileAdaptive CONSTANT) - Q_PROPERTY(bool pointerAccelerationProfileAdaptive READ pointerAccelerationProfileAdaptive WRITE setPointerAccelerationProfileAdaptive NOTIFY - pointerAccelerationProfileChanged) - - // - // tapping - Q_PROPERTY(int tapFingerCount READ tapFingerCount CONSTANT) - Q_PROPERTY(bool tapToClickEnabledByDefault READ tapToClickEnabledByDefault CONSTANT) - Q_PROPERTY(bool tapToClick READ isTapToClick WRITE setTapToClick NOTIFY tapToClickChanged) - - Q_PROPERTY(bool supportsLmrTapButtonMap READ supportsLmrTapButtonMap CONSTANT) - Q_PROPERTY(bool lmrTapButtonMapEnabledByDefault READ lmrTapButtonMapEnabledByDefault CONSTANT) - Q_PROPERTY(bool lmrTapButtonMap READ lmrTapButtonMap WRITE setLmrTapButtonMap NOTIFY lmrTapButtonMapChanged) - - Q_PROPERTY(bool tapAndDragEnabledByDefault READ tapAndDragEnabledByDefault CONSTANT) - Q_PROPERTY(bool tapAndDrag READ isTapAndDrag WRITE setTapAndDrag NOTIFY tapAndDragChanged) - - Q_PROPERTY(bool tapDragLockEnabledByDefault READ tapDragLockEnabledByDefault CONSTANT) - Q_PROPERTY(bool tapDragLock READ isTapDragLock WRITE setTapDragLock NOTIFY tapDragLockChanged) - - // - // scrolling - Q_PROPERTY(bool supportsNaturalScroll READ supportsNaturalScroll CONSTANT) - Q_PROPERTY(bool naturalScrollEnabledByDefault READ naturalScrollEnabledByDefault CONSTANT) - Q_PROPERTY(bool naturalScroll READ isNaturalScroll WRITE setNaturalScroll NOTIFY naturalScrollChanged) - - Q_PROPERTY(bool supportsHorizontalScrolling READ supportsHorizontalScrolling CONSTANT) - Q_PROPERTY(bool horizontalScrollingByDefault READ horizontalScrollingByDefault CONSTANT) - Q_PROPERTY(bool horizontalScrolling READ horizontalScrolling WRITE setHorizontalScrolling NOTIFY horizontalScrollingChanged) - - Q_PROPERTY(bool supportsScrollTwoFinger READ supportsScrollTwoFinger CONSTANT) - Q_PROPERTY(bool scrollTwoFingerEnabledByDefault READ scrollTwoFingerEnabledByDefault CONSTANT) - Q_PROPERTY(bool scrollTwoFinger READ isScrollTwoFinger WRITE setScrollTwoFinger NOTIFY scrollMethodChanged) - - Q_PROPERTY(bool supportsScrollEdge READ supportsScrollEdge CONSTANT) - Q_PROPERTY(bool scrollEdgeEnabledByDefault READ scrollEdgeEnabledByDefault CONSTANT) - Q_PROPERTY(bool scrollEdge READ isScrollEdge WRITE setScrollEdge NOTIFY scrollMethodChanged) - - Q_PROPERTY(bool supportsScrollOnButtonDown READ supportsScrollOnButtonDown CONSTANT) - Q_PROPERTY(bool scrollOnButtonDownEnabledByDefault READ scrollOnButtonDownEnabledByDefault CONSTANT) - Q_PROPERTY(bool scrollOnButtonDown READ isScrollOnButtonDown WRITE setScrollOnButtonDown NOTIFY scrollMethodChanged) - - Q_PROPERTY(quint32 defaultScrollButton READ defaultScrollButton CONSTANT) - Q_PROPERTY(quint32 scrollButton READ scrollButton WRITE setScrollButton NOTIFY scrollButtonChanged) - - // Click Methods - Q_PROPERTY(bool supportsClickMethodAreas READ supportsClickMethodAreas CONSTANT) - Q_PROPERTY(bool defaultClickMethodAreas READ defaultClickMethodAreas CONSTANT) - Q_PROPERTY(bool clickMethodAreas READ isClickMethodAreas WRITE setClickMethodAreas NOTIFY clickMethodChanged) - - Q_PROPERTY(bool supportsClickMethodClickfinger READ supportsClickMethodClickfinger CONSTANT) - Q_PROPERTY(bool defaultClickMethodClickfinger READ defaultClickMethodClickfinger CONSTANT) - Q_PROPERTY(bool clickMethodClickfinger READ isClickMethodClickfinger WRITE setClickMethodClickfinger NOTIFY clickMethodChanged) - - Q_PROPERTY(bool supportsScrollFactor READ supportsScrollFactor CONSTANT) -public: - LibinputCommon() - { - } - virtual ~LibinputCommon() - { - } - - virtual QString name() const = 0; - virtual bool supportsDisableEvents() const = 0; - virtual bool isEnabled() const = 0; - virtual void setEnabled(bool set) = 0; - - // - // advanced - Qt::MouseButtons supportedButtons() const - { - return m_supportedButtons.val; - } - - virtual bool supportsLeftHanded() const = 0; - bool leftHandedEnabledByDefault() const - { - return m_leftHandedEnabledByDefault.val; - } - bool isLeftHanded() const - { - return m_leftHanded.val; - } - void setLeftHanded(bool set) - { - m_leftHanded.set(set); - } - - virtual bool supportsDisableEventsOnExternalMouse() const = 0; - - virtual bool supportsDisableWhileTyping() const = 0; - bool disableWhileTypingEnabledByDefault() const - { - return m_disableWhileTypingEnabledByDefault.val; - } - bool isDisableWhileTyping() const - { - return m_disableWhileTyping.val; - } - void setDisableWhileTyping(bool set) - { - m_disableWhileTyping.set(set); - } - - virtual bool supportsMiddleEmulation() const = 0; - bool middleEmulationEnabledByDefault() const - { - return m_middleEmulationEnabledByDefault.val; - } - bool isMiddleEmulation() const - { - return m_middleEmulation.val; - } - void setMiddleEmulation(bool set) - { - m_middleEmulation.set(set); - } - - virtual bool supportsPointerAcceleration() const = 0; - qreal pointerAcceleration() const - { - return m_pointerAcceleration.val; - } - void setPointerAcceleration(qreal acceleration) - { - m_pointerAcceleration.set(acceleration); - } - - virtual bool supportsPointerAccelerationProfileFlat() const = 0; - bool defaultPointerAccelerationProfileFlat() const - { - return m_defaultPointerAccelerationProfileFlat.val; - } - bool pointerAccelerationProfileFlat() const - { - return m_pointerAccelerationProfileFlat.val; - } - void setPointerAccelerationProfileFlat(bool set) - { - m_pointerAccelerationProfileFlat.set(set); - } - - virtual bool supportsPointerAccelerationProfileAdaptive() const = 0; - bool defaultPointerAccelerationProfileAdaptive() const - { - return m_defaultPointerAccelerationProfileAdaptive.val; - } - bool pointerAccelerationProfileAdaptive() const - { - return m_pointerAccelerationProfileAdaptive.val; - } - void setPointerAccelerationProfileAdaptive(bool set) - { - m_pointerAccelerationProfileAdaptive.set(set); - } - - // - // scrolling - virtual bool supportsNaturalScroll() const = 0; - bool naturalScrollEnabledByDefault() const - { - return m_naturalScrollEnabledByDefault.val; - } - bool isNaturalScroll() const - { - return m_naturalScroll.val; - } - void setNaturalScroll(bool set) - { - m_naturalScroll.set(set); - } - - virtual bool supportsHorizontalScrolling() const = 0; - bool horizontalScrollingByDefault() const - { - return true; - } - bool horizontalScrolling() const - { - return m_horizontalScrolling.val; - } - void setHorizontalScrolling(bool set) - { - m_horizontalScrolling.set(set); - } - - virtual bool supportsScrollTwoFinger() const = 0; - bool scrollTwoFingerEnabledByDefault() const - { - return m_scrollTwoFingerEnabledByDefault.val; - } - bool isScrollTwoFinger() const - { - return m_isScrollTwoFinger.val; - } - void setScrollTwoFinger(bool set) - { - m_isScrollTwoFinger.set(set); - } - - virtual bool supportsScrollEdge() const = 0; - bool scrollEdgeEnabledByDefault() const - { - return m_scrollEdgeEnabledByDefault.val; - } - bool isScrollEdge() const - { - return m_isScrollEdge.val; - } - void setScrollEdge(bool set) - { - m_isScrollEdge.set(set); - } - - virtual bool supportsScrollOnButtonDown() const = 0; - bool scrollOnButtonDownEnabledByDefault() const - { - return m_scrollOnButtonDownEnabledByDefault.val; - } - bool isScrollOnButtonDown() const - { - return m_isScrollOnButtonDown.val; - } - void setScrollOnButtonDown(bool set) - { - m_isScrollOnButtonDown.set(set); - } - - quint32 defaultScrollButton() const - { - return m_defaultScrollButton.val; - } - quint32 scrollButton() const - { - return m_scrollButton.val; - } - void setScrollButton(quint32 button) - { - m_scrollButton.set(button); - } - - // - // tapping - int tapFingerCount() const - { - return m_tapFingerCount.val; - } - bool tapToClickEnabledByDefault() const - { - return m_tapToClickEnabledByDefault.val; - } - bool isTapToClick() const - { - return m_tapToClick.val; - } - void setTapToClick(bool set) - { - m_tapToClick.set(set); - } - - bool supportsLmrTapButtonMap() const - { - return m_tapFingerCount.val > 1; - } - bool lmrTapButtonMapEnabledByDefault() const - { - return m_lmrTapButtonMapEnabledByDefault.val; - } - bool lmrTapButtonMap() const - { - return m_lmrTapButtonMap.val; - } - virtual void setLmrTapButtonMap(bool set) = 0; - - bool tapAndDragEnabledByDefault() const - { - return m_tapAndDragEnabledByDefault.val; - } - bool isTapAndDrag() const - { - return m_tapAndDrag.val; - } - void setTapAndDrag(bool set) - { - m_tapAndDrag.set(set); - } - - bool tapDragLockEnabledByDefault() const - { - return m_tapDragLockEnabledByDefault.val; - } - bool isTapDragLock() const - { - return m_tapDragLock.val; - } - void setTapDragLock(bool set) - { - m_tapDragLock.set(set); - } - - // - // click method - virtual bool supportsClickMethodAreas() const = 0; - bool defaultClickMethodAreas() const - { - return m_defaultClickMethodAreas.val; - } - bool isClickMethodAreas() const - { - return m_clickMethodAreas.val; - } - void setClickMethodAreas(bool set) - { - m_clickMethodAreas.set(set); - } - - virtual bool supportsClickMethodClickfinger() const = 0; - bool defaultClickMethodClickfinger() const - { - return m_defaultClickMethodClickfinger.val; - } - bool isClickMethodClickfinger() const - { - return m_clickMethodClickfinger.val; - } - void setClickMethodClickfinger(bool set) - { - m_clickMethodClickfinger.set(set); - } - - virtual bool supportsScrollFactor() const = 0; - -Q_SIGNALS: - void enabledChanged(); - // Tapping - void tapToClickChanged(); - void lmrTapButtonMapChanged(); - void tapAndDragChanged(); - void tapDragLockChanged(); - // Advanced - void leftHandedChanged(); - void disableWhileTypingChanged(); - void middleEmulationChanged(); - // acceleration speed and profile - void pointerAccelerationChanged(); - void pointerAccelerationProfileChanged(); - // scrolling - void naturalScrollChanged(); - void horizontalScrollingChanged(); - void scrollMethodChanged(); - void scrollButtonChanged(); - // click methods - void clickMethodChanged(); - -protected: - template - struct Prop { - explicit Prop(const QByteArray &name) - : name(name) - { - } - - void set(T newVal) - { - if (avail && val != newVal) { - val = newVal; - } - } - void set(const Prop &p) - { - if (avail && val != p.val) { - val = p.val; - } - } - bool changed() const - { - return avail && (old != val); - } - - // In wayland, name will be dbus name - QByteArray name; - bool avail; - T old; - T val; - }; - - // - // general - Prop m_supportsDisableEvents = Prop("supportsDisableEvents"); - Prop m_enabledDefault = Prop("enabledDefault"); - Prop m_enabled = Prop("enabled"); - - // - // advanced - Prop m_supportedButtons = Prop("supportedButtons"); - - Prop m_leftHandedEnabledByDefault = Prop("leftHandedEnabledByDefault"); - Prop m_leftHanded = Prop("leftHanded"); - - Prop m_supportsDisableEventsOnExternalMouse = Prop("supportsDisableEventsOnExternalMouse"); - - Prop m_disableWhileTypingEnabledByDefault = Prop("disableWhileTypingEnabledByDefault"); - Prop m_disableWhileTyping = Prop("disableWhileTyping"); - - Prop m_middleEmulationEnabledByDefault = Prop("middleEmulationEnabledByDefault"); - Prop m_middleEmulation = Prop("middleEmulation"); - - // - // acceleration speed and profile - Prop m_defaultPointerAcceleration = Prop("defaultPointerAcceleration"); - Prop m_pointerAcceleration = Prop("pointerAcceleration"); - - Prop m_supportsPointerAccelerationProfileFlat = Prop("supportsPointerAccelerationProfileFlat"); - Prop m_defaultPointerAccelerationProfileFlat = Prop("defaultPointerAccelerationProfileFlat"); - Prop m_pointerAccelerationProfileFlat = Prop("pointerAccelerationProfileFlat"); - - Prop m_supportsPointerAccelerationProfileAdaptive = Prop("supportsPointerAccelerationProfileAdaptive"); - Prop m_defaultPointerAccelerationProfileAdaptive = Prop("defaultPointerAccelerationProfileAdaptive"); - Prop m_pointerAccelerationProfileAdaptive = Prop("pointerAccelerationProfileAdaptive"); - - // - // tapping - Prop m_tapFingerCount = Prop("tapFingerCount"); - Prop m_tapToClickEnabledByDefault = Prop("tapToClickEnabledByDefault"); - Prop m_tapToClick = Prop("tapToClick"); - - Prop m_lmrTapButtonMapEnabledByDefault = Prop("lmrTapButtonMapEnabledByDefault"); - Prop m_lmrTapButtonMap = Prop("lmrTapButtonMap"); - - Prop m_tapAndDragEnabledByDefault = Prop("tapAndDragEnabledByDefault"); - Prop m_tapAndDrag = Prop("tapAndDrag"); - Prop m_tapDragLockEnabledByDefault = Prop("tapDragLockEnabledByDefault"); - Prop m_tapDragLock = Prop("tapDragLock"); - - // - // scrolling - Prop m_naturalScrollEnabledByDefault = Prop("naturalScrollEnabledByDefault"); - Prop m_naturalScroll = Prop("naturalScroll"); - - Prop m_horizontalScrolling = Prop("horizontalScrolling"); - - Prop m_supportsScrollTwoFinger = Prop("supportsScrollTwoFinger"); - Prop m_scrollTwoFingerEnabledByDefault = Prop("scrollTwoFingerEnabledByDefault"); - Prop m_isScrollTwoFinger = Prop("scrollTwoFinger"); - - Prop m_supportsScrollEdge = Prop("supportsScrollEdge"); - Prop m_scrollEdgeEnabledByDefault = Prop("scrollEdgeEnabledByDefault"); - Prop m_isScrollEdge = Prop("scrollEdge"); - - Prop m_supportsScrollOnButtonDown = Prop("supportsScrollOnButtonDown"); - Prop m_scrollOnButtonDownEnabledByDefault = Prop("scrollOnButtonDownEnabledByDefault"); - Prop m_isScrollOnButtonDown = Prop("scrollOnButtonDown"); - - Prop m_defaultScrollButton = Prop("defaultScrollButton"); - Prop m_scrollButton = Prop("scrollButton"); - - // Click Method - Prop m_supportsClickMethodAreas = Prop("supportsClickMethodAreas"); - Prop m_defaultClickMethodAreas = Prop("defaultClickMethodAreas"); - Prop m_clickMethodAreas = Prop("clickMethodAreas"); - - Prop m_supportsClickMethodClickfinger = Prop("supportsClickMethodClickfinger"); - Prop m_defaultClickMethodClickfinger = Prop("defaultClickMethodClickfinger"); - Prop m_clickMethodClickfinger = Prop("clickMethodClickfinger"); -}; - -#endif // LIBINPUTCOMMON_H diff --git a/settings-daemon/touchpad/touchpadmanager.cpp b/settings-daemon/touchpad/touchpadmanager.cpp index dba99f6..0f7201a 100644 --- a/settings-daemon/touchpad/touchpadmanager.cpp +++ b/settings-daemon/touchpad/touchpadmanager.cpp @@ -1,66 +1,80 @@ #include "touchpadmanager.h" #include "touchpadadaptor.h" -#include +#include "input/kwininputbackend.h" + +#include TouchpadManager::TouchpadManager(QObject *parent) : QObject(parent) - , m_backend(XlibBackend::initialize()) + , m_backend(new KWinInputBackend(KWinInputBackend::DeviceType::Touchpad, this)) { - // init dbus new TouchpadAdaptor(this); QDBusConnection::sessionBus().registerObject(QStringLiteral("/Touchpad"), this); - m_backend->getConfig(); - m_backend->applyConfig(); + connect(m_backend, &KWinInputBackend::devicesChanged, this, [this] { + emit availableChanged(); + emit enabledChanged(); + emit tapToClickChanged(); + emit naturalScrollChanged(); + emit pointerAccelerationChanged(); + }); } bool TouchpadManager::available() const { - return m_backend->isTouchpadAvailable(); + return m_backend->available(); } bool TouchpadManager::enabled() const { - return m_backend->isTouchpadEnabled(); + return m_backend->booleanProperty(QStringLiteral("enabled"), true); } void TouchpadManager::setEnabled(bool enabled) { - m_backend->setTouchpadEnabled(enabled); - m_backend->applyConfig(); + if (this->enabled() == enabled) + return; + m_backend->setBooleanProperty(QStringLiteral("enabled"), enabled); + emit enabledChanged(); } bool TouchpadManager::tapToClick() const { - return m_backend->tapToClick(); + return m_backend->booleanProperty(QStringLiteral("tapToClick")); } void TouchpadManager::setTapToClick(bool value) { - m_backend->setTapToClick(value); - m_backend->applyConfig(); + if (tapToClick() == value) + return; + m_backend->setBooleanProperty(QStringLiteral("tapToClick"), value); + emit tapToClickChanged(); } bool TouchpadManager::naturalScroll() const { - return m_backend->naturalScroll(); + return m_backend->booleanProperty(QStringLiteral("naturalScroll")); } void TouchpadManager::setNaturalScroll(bool naturalScroll) { - m_backend->setNaturalScroll(naturalScroll); - m_backend->applyConfig(); + if (this->naturalScroll() == naturalScroll) + return; + m_backend->setBooleanProperty(QStringLiteral("naturalScroll"), naturalScroll); + emit naturalScrollChanged(); } qreal TouchpadManager::pointerAcceleration() const { - return m_backend->pointerAcceleration(); + return m_backend->realProperty(QStringLiteral("pointerAcceleration")); } void TouchpadManager::setPointerAcceleration(qreal value) { - qDebug() << value; - m_backend->setPointerAcceleration(value); - m_backend->applyConfig(); + value = qBound(-1.0, value, 1.0); + if (qFuzzyCompare(1.0 + pointerAcceleration(), 1.0 + value)) + return; + m_backend->setRealProperty(QStringLiteral("pointerAcceleration"), value); + emit pointerAccelerationChanged(); } diff --git a/settings-daemon/touchpad/touchpadmanager.h b/settings-daemon/touchpad/touchpadmanager.h index d8f84d6..7d61641 100644 --- a/settings-daemon/touchpad/touchpadmanager.h +++ b/settings-daemon/touchpad/touchpadmanager.h @@ -2,16 +2,17 @@ #define TOUCHPADMANAGER_H #include -#include "x11/xlibbackend.h" + +class KWinInputBackend; class TouchpadManager : public QObject { Q_OBJECT - Q_PROPERTY(bool available READ available CONSTANT) - Q_PROPERTY(bool enabled READ enabled WRITE setEnabled CONSTANT) - Q_PROPERTY(bool tapToClick READ tapToClick WRITE setTapToClick CONSTANT) - Q_PROPERTY(bool naturalScroll READ naturalScroll WRITE setNaturalScroll CONSTANT) - Q_PROPERTY(qreal pointerAcceleration READ pointerAcceleration WRITE setPointerAcceleration CONSTANT) + Q_PROPERTY(bool available READ available NOTIFY availableChanged) + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) + Q_PROPERTY(bool tapToClick READ tapToClick WRITE setTapToClick NOTIFY tapToClickChanged) + Q_PROPERTY(bool naturalScroll READ naturalScroll WRITE setNaturalScroll NOTIFY naturalScrollChanged) + Q_PROPERTY(qreal pointerAcceleration READ pointerAcceleration WRITE setPointerAcceleration NOTIFY pointerAccelerationChanged) public: explicit TouchpadManager(QObject *parent = nullptr); @@ -30,8 +31,15 @@ public: qreal pointerAcceleration() const; void setPointerAcceleration(qreal value); +signals: + void availableChanged(); + void enabledChanged(); + void tapToClickChanged(); + void naturalScrollChanged(); + void pointerAccelerationChanged(); + private: - XlibBackend *m_backend; + KWinInputBackend *m_backend; }; #endif // TOUCHPADMANAGER_H diff --git a/settings-daemon/touchpad/x11/libinputtouchpad.cpp b/settings-daemon/touchpad/x11/libinputtouchpad.cpp deleted file mode 100644 index c6c7b7e..0000000 --- a/settings-daemon/touchpad/x11/libinputtouchpad.cpp +++ /dev/null @@ -1,401 +0,0 @@ -/* - SPDX-FileCopyrightText: 2019 Atul Bisht - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#include "libinputtouchpad.h" - -#include -#include - -#include -#include - -#include -#include - -#include - -const Parameter libinputProperties[] = { - - /* libinput disable supports property */ - {"supportsDisableEvents", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_AVAILABLE, 8, 0}, - {"enabled", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_ENABLED, 8, 0}, - {"enabledDefault", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_ENABLED_DEFAULT, 8, 0}, - - /* LeftHandSupport */ - {"leftHandedEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_LEFT_HANDED_DEFAULT, 8, 0}, - {"leftHanded", PT_INT, 0, 1, LIBINPUT_PROP_LEFT_HANDED, 8, 0}, - - /* Disable on external mouse */ - {"supportsDisableEventsOnExternalMouse", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_AVAILABLE, 8, 1}, - {"disableEventsOnExternalMouse", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_ENABLED, 8, 1}, - {"disableEventsOnExternalMouseDefault", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_ENABLED_DEFAULT, 8, 1}, - - /* Disable while typing */ - {"disableWhileTypingEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_DISABLE_WHILE_TYPING_DEFAULT, 8, 0}, - {"disableWhileTyping", PT_INT, 0, 1, LIBINPUT_PROP_DISABLE_WHILE_TYPING, 8, 0}, - - /* Middle Emulation */ - {"middleEmulationEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_MIDDLE_EMULATION_ENABLED_DEFAULT, 8, 0}, - {"middleEmulation", PT_INT, 0, 1, LIBINPUT_PROP_MIDDLE_EMULATION_ENABLED, 8, 0}, - - /* This is a boolean for all three fingers, no per-finger config */ - {"tapToClick", PT_INT, 0, 1, LIBINPUT_PROP_TAP, 8, 0}, - {"tapToClickEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_TAP_DEFAULT, 8, 0}, - - /* LMR */ - {"lrmTapButtonMapEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_TAP_BUTTONMAP_DEFAULT, 8, 0}, - {"lrmTapButtonMap", PT_INT, 0, 1, LIBINPUT_PROP_TAP_BUTTONMAP, 8, 0}, - {"lmrTapButtonMapEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_TAP_BUTTONMAP_DEFAULT, 8, 1}, - {"lmrTapButtonMap", PT_INT, 0, 1, LIBINPUT_PROP_TAP_BUTTONMAP, 8, 1}, - - /* Tap and Drag Enabled */ - {"tapAndDragEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_TAP_DRAG_DEFAULT, 8, 0}, - {"tapAndDrag", PT_INT, 0, 1, LIBINPUT_PROP_TAP_DRAG, 8, 0}, - - /* Tap and Drag Lock Enabled */ - {"tapDragLockEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_TAP_DRAG_LOCK_DEFAULT, 8, 0}, - {"tapDragLock", PT_INT, 0, 1, LIBINPUT_PROP_TAP_DRAG_LOCK, 8, 0}, - - /* libinput normalizes the accel to -1/1 */ - {"defaultPointerAcceleration", PT_DOUBLE, -1.0, 1.0, LIBINPUT_PROP_ACCEL_DEFAULT, 0 /*float */, 0}, - {"pointerAcceleration", PT_DOUBLE, -1.0, 1.0, LIBINPUT_PROP_ACCEL, 0 /*float */, 0}, - - /* Libinput Accel Profile */ - {"supportsPointerAccelerationProfileAdaptive", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILES_AVAILABLE, 8, 0}, - {"defaultPointerAccelerationProfileAdaptive", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED_DEFAULT, 8, 0}, - {"pointerAccelerationProfileAdaptive", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, 8, 0}, - {"supportsPointerAccelerationProfileFlat", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILES_AVAILABLE, 8, 1}, - {"defaultPointerAccelerationProfileFlat", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED_DEFAULT, 8, 1}, - {"pointerAccelerationProfileFlat", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, 8, 1}, - - /* Natural Scrolling */ - {"naturalScrollEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_NATURAL_SCROLL_DEFAULT, 8, 0}, - {"naturalScroll", PT_INT, 0, 1, LIBINPUT_PROP_NATURAL_SCROLL, 8, 0}, - - /* Horizontal scrolling */ - {"horizontalScrolling", PT_INT, 0, 1, LIBINPUT_PROP_HORIZ_SCROLL_ENABLED, 8, 0}, - - /* Two-Finger Scrolling */ - {"supportsScrollTwoFinger", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHODS_AVAILABLE, 8, 0}, - {"scrollTwoFingerEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED_DEFAULT, 8, 0}, - {"scrollTwoFinger", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED, 8, 0}, - - /* Edge Scrolling */ - {"supportsScrollEdge", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHODS_AVAILABLE, 8, 1}, - {"scrollEdgeEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED_DEFAULT, 8, 1}, - {"scrollEdge", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED, 8, 1}, - - /* scroll on button */ - {"supportsScrollOnButtonDown", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHODS_AVAILABLE, 8, 2}, - {"scrollOnButtonDownEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED_DEFAULT, 8, 2}, - {"scrollOnButtonDown", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED, 8, 2}, - - /* Scroll Button for scroll on button Down */ - {"defaultScrollButton", PT_INT, 0, INT_MAX, LIBINPUT_PROP_SCROLL_BUTTON_DEFAULT, 32, 0}, - {"scrollButton", PT_INT, 0, INT_MAX, LIBINPUT_PROP_SCROLL_BUTTON, 32, 0}, - - /* Click Methods */ - {"supportsClickMethodAreas", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHODS_AVAILABLE, 8, 0}, - {"defaultClickMethodAreas", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHOD_ENABLED_DEFAULT, 8, 0}, - {"clickMethodAreas", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHOD_ENABLED, 8, 0}, - - {"supportsClickMethodClickfinger", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHODS_AVAILABLE, 8, 1}, - {"defaultClickMethodClickfinger", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHOD_ENABLED_DEFAULT, 8, 1}, - {"clickMethodClickfinger", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHOD_ENABLED, 8, 1}, - - /* libinput doesn't have a separate toggle for horiz scrolling */ - {nullptr, PT_INT, 0, 0, nullptr, 0, 0}}; - -Qt::MouseButtons maskBtns(Display *display, XIButtonClassInfo *buttonInfo) -{ - Qt::MouseButtons buttons = Qt::NoButton; - for (int i = 0; i < buttonInfo->num_buttons; ++i) { - QByteArray reply = XGetAtomName(display, buttonInfo->labels[i]); - - if (reply == BTN_LABEL_PROP_BTN_LEFT) { - buttons |= Qt::LeftButton; - } - if (reply == BTN_LABEL_PROP_BTN_RIGHT) { - buttons |= Qt::RightButton; - } - if (reply == BTN_LABEL_PROP_BTN_MIDDLE) { - buttons |= Qt::MiddleButton; - } - if (reply == BTN_LABEL_PROP_BTN_SIDE) { - buttons |= Qt::ExtraButton1; - } - if (reply == BTN_LABEL_PROP_BTN_EXTRA) { - buttons |= Qt::ExtraButton2; - } - if (reply == BTN_LABEL_PROP_BTN_FORWARD) { - buttons |= Qt::ForwardButton; - } - if (reply == BTN_LABEL_PROP_BTN_BACK) { - buttons |= Qt::BackButton; - } - if (reply == BTN_LABEL_PROP_BTN_TASK) { - buttons |= Qt::TaskButton; - } - } - return buttons; -} - -LibinputTouchpad::LibinputTouchpad(Display *display, int deviceId) - : LibinputCommon() - , XlibTouchpad(display, deviceId) - , m_config("cutefishos", "touchpadxlibinputrc") -{ - loadSupportedProperties(libinputProperties); - - int nDevices = 0; - XIDeviceInfo *deviceInfo = XIQueryDevice(m_display, m_deviceId, &nDevices); - m_name = deviceInfo->name; - - for (int i = 0; i < deviceInfo->num_classes; ++i) { - XIAnyClassInfo *classInfo = deviceInfo->classes[i]; - - if (classInfo->type == XIButtonClass) { - XIButtonClassInfo *btnInfo = (XIButtonClassInfo *)classInfo; - m_supportedButtons.avail = true; - m_supportedButtons.set(maskBtns(m_display, btnInfo)); - } - if (classInfo->type == XITouchClass) { - XITouchClassInfo *touchInfo = (XITouchClassInfo *)classInfo; - m_tapFingerCount.avail = true; - m_tapFingerCount.set(touchInfo->num_touches); - } - } - XIFreeDeviceInfo(deviceInfo); - - /* FingerCount cannot be zero */ - if (!m_tapFingerCount.val) { - m_tapFingerCount.avail = true; - m_tapFingerCount.set(1); - } -} - -bool LibinputTouchpad::getConfig() -{ - bool success = true; - - success &= valueLoader(m_supportsDisableEvents); - success &= valueLoader(m_enabled); - success &= valueLoader(m_enabledDefault); - - success &= valueLoader(m_tapToClickEnabledByDefault); - success &= valueLoader(m_tapToClick); - success &= valueLoader(m_lrmTapButtonMapEnabledByDefault); - success &= valueLoader(m_lrmTapButtonMap); - success &= valueLoader(m_lmrTapButtonMapEnabledByDefault); - success &= valueLoader(m_lmrTapButtonMap); - success &= valueLoader(m_tapAndDragEnabledByDefault); - success &= valueLoader(m_tapAndDrag); - success &= valueLoader(m_tapDragLockEnabledByDefault); - success &= valueLoader(m_tapDragLock); - - success &= valueLoader(m_leftHandedEnabledByDefault); - success &= valueLoader(m_leftHanded); - - success &= valueLoader(m_supportsDisableEventsOnExternalMouse); - success &= valueLoader(m_disableEventsOnExternalMouse); - success &= valueLoader(m_disableEventsOnExternalMouseDefault); - - success &= valueLoader(m_disableWhileTypingEnabledByDefault); - success &= valueLoader(m_disableWhileTyping); - - success &= valueLoader(m_middleEmulationEnabledByDefault); - success &= valueLoader(m_middleEmulation); - - success &= valueLoader(m_defaultPointerAcceleration); - success &= valueLoader(m_pointerAcceleration); - - success &= valueLoader(m_supportsPointerAccelerationProfileFlat); - success &= valueLoader(m_defaultPointerAccelerationProfileFlat); - success &= valueLoader(m_pointerAccelerationProfileFlat); - success &= valueLoader(m_supportsPointerAccelerationProfileAdaptive); - success &= valueLoader(m_defaultPointerAccelerationProfileAdaptive); - success &= valueLoader(m_pointerAccelerationProfileAdaptive); - - success &= valueLoader(m_naturalScrollEnabledByDefault); - success &= valueLoader(m_naturalScroll); - - success &= valueLoader(m_horizontalScrolling); - - success &= valueLoader(m_supportsScrollTwoFinger); - success &= valueLoader(m_scrollTwoFingerEnabledByDefault); - success &= valueLoader(m_isScrollTwoFinger); - - success &= valueLoader(m_supportsScrollEdge); - success &= valueLoader(m_scrollEdgeEnabledByDefault); - success &= valueLoader(m_isScrollEdge); - - success &= valueLoader(m_supportsScrollOnButtonDown); - success &= valueLoader(m_scrollOnButtonDownEnabledByDefault); - success &= valueLoader(m_isScrollOnButtonDown); - - success &= valueLoader(m_defaultScrollButton); - success &= valueLoader(m_scrollButton); - - // click methods - success &= valueLoader(m_supportsClickMethodAreas); - success &= valueLoader(m_supportsClickMethodClickfinger); - success &= valueLoader(m_defaultClickMethodAreas); - success &= valueLoader(m_defaultClickMethodClickfinger); - success &= valueLoader(m_clickMethodAreas); - success &= valueLoader(m_clickMethodClickfinger); - - return success; -} - -bool LibinputTouchpad::applyConfig() -{ - QVector msgs; - - msgs << valueWriter(m_enabled) << valueWriter(m_tapToClick) << valueWriter(m_lrmTapButtonMap) << valueWriter(m_lmrTapButtonMap) << valueWriter(m_tapAndDrag) - << valueWriter(m_tapDragLock) << valueWriter(m_leftHanded) << valueWriter(m_disableWhileTyping) << valueWriter(m_middleEmulation) - << valueWriter(m_pointerAcceleration) << valueWriter(m_pointerAccelerationProfileFlat) << valueWriter(m_pointerAccelerationProfileAdaptive) - << valueWriter(m_naturalScroll) << valueWriter(m_horizontalScrolling) << valueWriter(m_isScrollTwoFinger) << valueWriter(m_isScrollEdge) - << valueWriter(m_isScrollOnButtonDown) << valueWriter(m_scrollButton) << valueWriter(m_clickMethodAreas) << valueWriter(m_clickMethodClickfinger); - - bool success = true; - QString error_msg; - - for (QString m : msgs) { - if (!m.isNull()) { - // qCCritical(KCM_TOUCHPAD) << "in error:" << m; - if (!success) { - error_msg.append("\n"); - } - error_msg.append(m); - success = false; - } - } - - if (!success) { - // qCCritical(KCM_TOUCHPAD) << error_msg; - } - - flush(); - return success; -} - -bool LibinputTouchpad::getDefaultConfig() -{ - m_enabled.set(m_enabledDefault); - m_tapToClick.set(m_tapToClickEnabledByDefault); - m_lrmTapButtonMap.set(m_lrmTapButtonMap); - m_lmrTapButtonMap.set(m_lmrTapButtonMapEnabledByDefault); - m_tapAndDrag.set(m_tapAndDragEnabledByDefault); - m_tapDragLock.set(m_tapDragLockEnabledByDefault); - m_leftHanded.set(m_leftHandedEnabledByDefault); - m_disableEventsOnExternalMouse.set(m_disableEventsOnExternalMouseDefault); - m_disableWhileTyping.set(m_disableWhileTypingEnabledByDefault); - m_middleEmulation.set(m_middleEmulationEnabledByDefault); - m_pointerAcceleration.set(m_defaultPointerAcceleration); - m_pointerAccelerationProfileFlat.set(m_defaultPointerAccelerationProfileFlat); - m_pointerAccelerationProfileAdaptive.set(m_defaultPointerAccelerationProfileAdaptive); - m_naturalScroll.set(m_naturalScrollEnabledByDefault); - m_horizontalScrolling.set(true); - m_isScrollTwoFinger.set(m_scrollTwoFingerEnabledByDefault); - m_isScrollEdge.set(m_scrollEdgeEnabledByDefault); - m_isScrollOnButtonDown.set(m_scrollOnButtonDownEnabledByDefault); - m_scrollButton.set(m_defaultScrollButton); - m_clickMethodAreas.set(m_defaultClickMethodAreas); - m_clickMethodClickfinger.set(m_defaultClickMethodClickfinger); - - return true; -} - -bool LibinputTouchpad::isChangedConfig() -{ - // clang-format off - bool changed = m_enabled.changed() || - m_tapToClick.changed() || - m_lrmTapButtonMap.changed() || - m_lmrTapButtonMap.changed() || - m_tapAndDrag.changed() || - m_tapDragLock.changed() || - m_leftHanded.changed() || - m_disableEventsOnExternalMouse.changed() || - m_disableWhileTyping.changed() || - m_middleEmulation.changed() || - m_pointerAcceleration.changed() || - m_pointerAccelerationProfileFlat.changed() || - m_pointerAccelerationProfileAdaptive.changed() || - m_naturalScroll.changed() || - m_horizontalScrolling.changed() || - m_isScrollTwoFinger.changed() || - m_isScrollEdge.changed() || - m_isScrollOnButtonDown.changed() || - m_scrollButton.changed() || - m_clickMethodAreas.changed() || - m_clickMethodClickfinger.changed(); - // clang-format on - - return changed; -} - -int LibinputTouchpad::touchpadOff() -{ - return m_enabled.val; -} - -XcbAtom &LibinputTouchpad::touchpadOffAtom() -{ - return *m_atoms[QLatin1String(LIBINPUT_PROP_SENDEVENTS_ENABLED)].data(); -} - -template -bool LibinputTouchpad::valueLoader(Prop &prop) -{ - const Parameter *p = findParameter(QString::fromLatin1(prop.name)); - - if (!p) { - // qCCritical(KCM_TOUCHPAD) << "Error on read of " << QString::fromLatin1(prop.name); - } - - QVariant reply = getParameter(p); - if (!reply.isValid()) { - prop.avail = false; - return true; - } - prop.avail = true; - - m_config.beginGroup(m_name); - - const T replyValue = valueLoaderPart(reply); - const T loadedValue = m_config.value(prop.name, replyValue).toBool(); - prop.old = replyValue; - prop.val = loadedValue; - - m_config.endGroup(); - - return true; -} - -template -QString LibinputTouchpad::valueWriter(const Prop &prop) -{ - const Parameter *p = findParameter(QString::fromLatin1(prop.name)); - - // Reion - if (!p /*|| !prop.changed()*/) { - return QString(); - } - - bool error = !setParameter(p, prop.val); - if (error) { - // qCCritical(KCM_TOUCHPAD) << "Cannot set property " + QString::fromLatin1(prop.name); - return QStringLiteral("Cannot set property ") + QString::fromLatin1(prop.name); - } - - m_config.beginGroup(m_name); - m_config.setValue(prop.name, prop.val); - m_config.endGroup(); - m_config.sync(); - - return QString(); -} diff --git a/settings-daemon/touchpad/x11/libinputtouchpad.h b/settings-daemon/touchpad/x11/libinputtouchpad.h deleted file mode 100644 index c1b8a5a..0000000 --- a/settings-daemon/touchpad/x11/libinputtouchpad.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - SPDX-FileCopyrightText: 2019 Atul Bisht - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef LIBINPUTTOUCHPAD_H -#define LIBINPUTTOUCHPAD_H - -#include "../libinputcommon.h" -#include "xlibtouchpad.h" - -#include - -class LibinputTouchpad : public LibinputCommon, public XlibTouchpad -{ - Q_OBJECT - -public: - LibinputTouchpad(Display *display, int deviceId); - ~LibinputTouchpad() override - { - } - - bool getConfig() override; - bool applyConfig() override; - bool getDefaultConfig() override; - bool isChangedConfig() override; - - int touchpadOff() override; - XcbAtom &touchpadOffAtom() override; - -private: - template - bool valueLoader(Prop &prop); - - template - QString valueWriter(const Prop &prop); - - QSettings m_config; - - // - // general - QString name() const override - { - return m_name; - } - bool supportsDisableEvents() const override - { - return m_supportsDisableEvents.avail && m_supportsDisableEvents.val; - } - bool isEnabled() const override - { - return !m_enabled.val; - } - void setEnabled(bool set) override - { - m_enabled.set(!set); - } - // - // Tapping - void setLmrTapButtonMap(bool set) override - { - m_lrmTapButtonMap.set(!set); - m_lmrTapButtonMap.set(set); - } - // - // advanced - bool supportsLeftHanded() const override - { - return m_leftHanded.avail; - } - bool supportsDisableEventsOnExternalMouse() const override - { - return m_supportsDisableEventsOnExternalMouse.avail && m_supportsDisableEventsOnExternalMouse.val; - } - bool supportsDisableWhileTyping() const override - { - return m_disableWhileTyping.avail; - } - bool supportsMiddleEmulation() const override - { - return m_middleEmulation.avail; - } - // - // acceleration speed and profile - bool supportsPointerAcceleration() const override - { - return m_pointerAcceleration.avail; - } - bool supportsPointerAccelerationProfileFlat() const override - { - return m_supportsPointerAccelerationProfileFlat.avail && m_supportsPointerAccelerationProfileFlat.val; - } - bool supportsPointerAccelerationProfileAdaptive() const override - { - return m_supportsPointerAccelerationProfileAdaptive.avail && m_supportsPointerAccelerationProfileAdaptive.val; - } - // - // scrolling - bool supportsNaturalScroll() const override - { - return m_naturalScroll.avail; - } - bool supportsHorizontalScrolling() const override - { - return true; - } - bool supportsScrollTwoFinger() const override - { - return m_supportsScrollTwoFinger.avail && m_supportsScrollTwoFinger.val; - } - bool supportsScrollEdge() const override - { - return m_supportsScrollEdge.avail && m_supportsScrollEdge.val; - } - bool supportsScrollOnButtonDown() const override - { - return m_supportsScrollOnButtonDown.avail && m_supportsScrollOnButtonDown.val; - } - // - // click method - bool supportsClickMethodAreas() const override - { - return m_supportsClickMethodAreas.avail && m_supportsClickMethodAreas.val; - } - bool supportsClickMethodClickfinger() const override - { - return m_supportsClickMethodClickfinger.avail && m_supportsClickMethodClickfinger.val; - } - - bool supportsScrollFactor() const override - { - return false; - } - - // Tapping - Prop m_lrmTapButtonMapEnabledByDefault = Prop("lrmTapButtonMapEnabledByDefault"); - Prop m_lrmTapButtonMap = Prop("lrmTapButtonMap"); - // - // advanced - Prop m_disableEventsOnExternalMouse = Prop("disableEventsOnExternalMouse"); - Prop m_disableEventsOnExternalMouseDefault = Prop("disableEventsOnExternalMouseDefault"); - - QString m_name; -}; - -#endif // LIBINPUTTOUCHPAD_H diff --git a/settings-daemon/touchpad/x11/propertyinfo.cpp b/settings-daemon/touchpad/x11/propertyinfo.cpp deleted file mode 100644 index 12e4a8a..0000000 --- a/settings-daemon/touchpad/x11/propertyinfo.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013 Alexander Mezin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#include "propertyinfo.h" - -#include -#include - -#include -#include -#include - -void XDeleter(void *p) -{ - if (p) { - XFree(p); - } -} - -PropertyInfo::PropertyInfo() - : type(0) - , format(0) - , nitems(0) - , f(nullptr) - , i(nullptr) - , b(nullptr) - , display(nullptr) - , device(0) - , prop(0) -{ -} - -PropertyInfo::PropertyInfo(Display *display, int device, Atom prop, Atom floatType) - : type(0) - , format(0) - , nitems(0) - , f(nullptr) - , i(nullptr) - , b(nullptr) - , display(display) - , device(device) - , prop(prop) -{ - unsigned char *dataPtr = nullptr; - unsigned long bytes_after; - XIGetProperty(display, device, prop, 0, 1000, False, AnyPropertyType, &type, &format, &nitems, &bytes_after, &dataPtr); - data = QSharedPointer(dataPtr, XDeleter); - - if (format == CHAR_BIT && type == XA_INTEGER) { - b = reinterpret_cast(dataPtr); - } - if (format == sizeof(int) * CHAR_BIT && (type == XA_INTEGER || type == XA_CARDINAL)) { - i = reinterpret_cast(dataPtr); - } - if (format == sizeof(float) * CHAR_BIT && floatType && type == floatType) { - f = reinterpret_cast(dataPtr); - } -} - -QVariant PropertyInfo::value(unsigned offset) const -{ - QVariant v; - if (offset >= nitems) { - return v; - } - - if (b) { - v = QVariant(static_cast(b[offset])); - } - if (i) { - v = QVariant(i[offset]); - } - if (f) { - v = QVariant(f[offset]); - } - - return v; -} - -void PropertyInfo::set() -{ - XIChangeProperty(display, device, prop, type, format, XIPropModeReplace, data.data(), nitems); -} diff --git a/settings-daemon/touchpad/x11/propertyinfo.h b/settings-daemon/touchpad/x11/propertyinfo.h deleted file mode 100644 index 0b660dc..0000000 --- a/settings-daemon/touchpad/x11/propertyinfo.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013 Alexander Mezin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef PROPERTYINFO_H -#define PROPERTYINFO_H - -#include -#include -#include - -void XDeleter(void *p); - -struct PropertyInfo { - Atom type; - int format; - QSharedPointer data; - unsigned long nitems; - - float *f; - int *i; - char *b; - - Display *display; - int device; - Atom prop; - - PropertyInfo(); - PropertyInfo(Display *display, int device, Atom prop, Atom floatType); - QVariant value(unsigned offset) const; - - void set(); -}; - -#endif // PROPERTYINFO_H diff --git a/settings-daemon/touchpad/x11/synapticstouchpad.cpp b/settings-daemon/touchpad/x11/synapticstouchpad.cpp deleted file mode 100644 index 37d60aa..0000000 --- a/settings-daemon/touchpad/x11/synapticstouchpad.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013 Alexander Mezin - SPDX-FileContributor: 2002-2005, 2007 Peter Osterlund - - SPDX-License-Identifier: GPL-2.0-or-later AND LicenseRef-synaptics -*/ - -#include -#include - -#include "synapticstouchpad.h" - -#include -#include -#include - -#define SYN_MAX_BUTTONS 12 - -const struct Parameter synapticsProperties[] = { - {"LeftEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_EDGES, 32, 0}, - {"RightEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_EDGES, 32, 1}, - {"TopEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_EDGES, 32, 2}, - {"BottomEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_EDGES, 32, 3}, - {"FingerLow", PT_INT, 0, 255, SYNAPTICS_PROP_FINGER, 32, 0}, - {"FingerHigh", PT_INT, 0, 255, SYNAPTICS_PROP_FINGER, 32, 1}, - {"MaxTapTime", PT_INT, 0, 1000, SYNAPTICS_PROP_TAP_TIME, 32, 0}, - {"MaxTapMove", PT_INT, 0, 2000, SYNAPTICS_PROP_TAP_MOVE, 32, 0}, - {"MaxDoubleTapTime", PT_INT, 0, 1000, SYNAPTICS_PROP_TAP_DURATIONS, 32, 1}, - {"SingleTapTimeout", PT_INT, 0, 1000, SYNAPTICS_PROP_TAP_DURATIONS, 32, 0}, - {"ClickTime", PT_INT, 0, 1000, SYNAPTICS_PROP_TAP_DURATIONS, 32, 2}, - {"FastTaps", PT_BOOL, 0, 1, SYNAPTICS_PROP_TAP_FAST, 8, 0}, - {"EmulateMidButtonTime", PT_INT, 0, 1000, SYNAPTICS_PROP_MIDDLE_TIMEOUT, 32, 0}, - {"EmulateTwoFingerMinZ", PT_INT, 0, 1000, SYNAPTICS_PROP_TWOFINGER_PRESSURE, 32, 0}, - {"EmulateTwoFingerMinW", PT_INT, 0, 15, SYNAPTICS_PROP_TWOFINGER_WIDTH, 32, 0}, - {"VertScrollDelta", PT_INT, -1000, 1000, SYNAPTICS_PROP_SCROLL_DISTANCE, 32, 0}, - {"HorizScrollDelta", PT_INT, -1000, 1000, SYNAPTICS_PROP_SCROLL_DISTANCE, 32, 1}, - {"VertEdgeScroll", PT_BOOL, 0, 1, SYNAPTICS_PROP_SCROLL_EDGE, 8, 0}, - {"HorizEdgeScroll", PT_BOOL, 0, 1, SYNAPTICS_PROP_SCROLL_EDGE, 8, 1}, - {"CornerCoasting", PT_BOOL, 0, 1, SYNAPTICS_PROP_SCROLL_EDGE, 8, 2}, - {"VertTwoFingerScroll", PT_BOOL, 0, 1, SYNAPTICS_PROP_SCROLL_TWOFINGER, 8, 0}, - {"HorizTwoFingerScroll", PT_BOOL, 0, 1, SYNAPTICS_PROP_SCROLL_TWOFINGER, 8, 1}, - {"MinSpeed", PT_DOUBLE, 0, 255.0, SYNAPTICS_PROP_SPEED, 0, /*float */ 0}, - {"MaxSpeed", PT_DOUBLE, 0, 255.0, SYNAPTICS_PROP_SPEED, 0, /*float */ 1}, - {"AccelFactor", PT_DOUBLE, 0, 1.0, SYNAPTICS_PROP_SPEED, 0, /*float */ 2}, - /*{"TouchpadOff", PT_INT, 0, 2, SYNAPTICS_PROP_OFF, 8, 0},*/ - {"LockedDrags", PT_BOOL, 0, 1, SYNAPTICS_PROP_LOCKED_DRAGS, 8, 0}, - {"LockedDragTimeout", PT_INT, 0, 30000, SYNAPTICS_PROP_LOCKED_DRAGS_TIMEOUT, 32, 0}, - {"RTCornerButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 0}, - {"RBCornerButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 1}, - {"LTCornerButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 2}, - {"LBCornerButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 3}, - {"OneFingerTapButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 4}, - {"TwoFingerTapButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 5}, - {"ThreeFingerTapButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 6}, - {"ClickFinger1", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_CLICK_ACTION, 8, 0}, - {"ClickFinger2", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_CLICK_ACTION, 8, 1}, - {"ClickFinger3", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_CLICK_ACTION, 8, 2}, - {"CircularScrolling", PT_BOOL, 0, 1, SYNAPTICS_PROP_CIRCULAR_SCROLLING, 8, 0}, - {"CircScrollDelta", PT_DOUBLE, .01, 3, SYNAPTICS_PROP_CIRCULAR_SCROLLING_DIST, 0 /* float */, 0}, - {"CircScrollTrigger", PT_INT, 0, 8, SYNAPTICS_PROP_CIRCULAR_SCROLLING_TRIGGER, 8, 0}, - {"PalmDetect", PT_BOOL, 0, 1, SYNAPTICS_PROP_PALM_DETECT, 8, 0}, - {"PalmMinWidth", PT_INT, 0, 15, SYNAPTICS_PROP_PALM_DIMENSIONS, 32, 0}, - {"PalmMinZ", PT_INT, 0, 255, SYNAPTICS_PROP_PALM_DIMENSIONS, 32, 1}, - {"CoastingSpeed", PT_DOUBLE, 0, 255, SYNAPTICS_PROP_COASTING_SPEED, 0 /* float*/, 0}, - {"CoastingFriction", PT_DOUBLE, 0, 255, SYNAPTICS_PROP_COASTING_SPEED, 0 /* float*/, 1}, - {"PressureMotionMinZ", PT_INT, 1, 255, SYNAPTICS_PROP_PRESSURE_MOTION, 32, 0}, - {"PressureMotionMaxZ", PT_INT, 1, 255, SYNAPTICS_PROP_PRESSURE_MOTION, 32, 1}, - {"PressureMotionMinFactor", PT_DOUBLE, 0, 10.0, SYNAPTICS_PROP_PRESSURE_MOTION_FACTOR, 0 /*float*/, 0}, - {"PressureMotionMaxFactor", PT_DOUBLE, 0, 10.0, SYNAPTICS_PROP_PRESSURE_MOTION_FACTOR, 0 /*float*/, 1}, - {"GrabEventDevice", PT_BOOL, 0, 1, SYNAPTICS_PROP_GRAB, 8, 0}, - {"TapAndDragGesture", PT_BOOL, 0, 1, SYNAPTICS_PROP_GESTURES, 8, 0}, - {"AreaLeftEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_AREA, 32, 0}, - {"AreaRightEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_AREA, 32, 1}, - {"AreaTopEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_AREA, 32, 2}, - {"AreaBottomEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_AREA, 32, 3}, - {"HorizHysteresis", PT_INT, 0, 10000, SYNAPTICS_PROP_NOISE_CANCELLATION, 32, 0}, - {"VertHysteresis", PT_INT, 0, 10000, SYNAPTICS_PROP_NOISE_CANCELLATION, 32, 1}, - {"ClickPad", PT_BOOL, 0, 1, SYNAPTICS_PROP_CLICKPAD, 8, 0}, - {"RightButtonAreaLeft", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 0}, - {"RightButtonAreaRight", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 1}, - {"RightButtonAreaTop", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 2}, - {"RightButtonAreaBottom", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 3}, - {"MiddleButtonAreaLeft", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 4}, - {"MiddleButtonAreaRight", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 5}, - {"MiddleButtonAreaTop", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 6}, - {"MiddleButtonAreaBottom", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 7}, - {NULL, PT_INT, 0, 0, nullptr, 0, 0}, -}; - -SynapticsTouchpad::SynapticsTouchpad(Display *display, int deviceId) - : XlibTouchpad(display, deviceId) - , m_resX(1) - , m_resY(1) -{ - m_capsAtom.intern(m_connection, SYNAPTICS_PROP_CAPABILITIES); - m_touchpadOffAtom.intern(m_connection, SYNAPTICS_PROP_OFF); - XcbAtom resolutionAtom(m_connection, SYNAPTICS_PROP_RESOLUTION); - XcbAtom edgesAtom(m_connection, SYNAPTICS_PROP_EDGES); - - loadSupportedProperties(synapticsProperties); - - m_toRadians.append("CircScrollDelta"); - - PropertyInfo edges(m_display, m_deviceId, edgesAtom, 0); - if (edges.i && edges.nitems == 4) { - int w = qAbs(edges.i[1] - edges.i[0]); - int h = qAbs(edges.i[3] - edges.i[2]); - m_resX = w / 90; - m_resY = h / 50; - qDebug() << "Width: " << w << " height: " << h; - qDebug() << "Approx. resX: " << m_resX << " resY: " << m_resY; - } - - PropertyInfo resolution(m_display, m_deviceId, resolutionAtom, 0); - if (resolution.i && resolution.nitems == 2 && resolution.i[0] > 1 && resolution.i[1] > 1) { - m_resY = qMin(static_cast(resolution.i[0]), static_cast(INT_MAX)); - m_resX = qMin(static_cast(resolution.i[1]), static_cast(INT_MAX)); - qDebug() << "Touchpad resolution: x: " << m_resX << " y: " << m_resY; - } - - m_scaleByResX.append("HorizScrollDelta"); - m_scaleByResY.append("VertScrollDelta"); - m_scaleByResX.append("MaxTapMove"); - m_scaleByResY.append("MaxTapMove"); - - m_resX = qMax(10, m_resX); - m_resY = qMax(10, m_resY); - qDebug() << "Final resolution x:" << m_resX << " y:" << m_resY; - m_negate["HorizScrollDelta"] = "InvertHorizScroll"; - m_negate["VertScrollDelta"] = "InvertVertScroll"; - m_supported.append(m_negate.values()); - m_supported.append("Coasting"); - - PropertyInfo caps(m_display, m_deviceId, m_capsAtom.atom(), 0); - if (!caps.b) { - return; - } - - enum TouchpadCapabilitiy { - TouchpadHasLeftButton, - TouchpadHasMiddleButton, - TouchpadHasRightButton, - TouchpadTwoFingerDetect, - TouchpadThreeFingerDetect, - TouchpadPressureDetect, - TouchpadPalmDetect, - TouchpadCapsCount, - }; - - QVector cap(TouchpadCapsCount, false); - std::copy(caps.b, caps.b + qMin(cap.size(), static_cast(caps.nitems)), cap.begin()); - - if (!cap[TouchpadTwoFingerDetect]) { - m_supported.removeAll("HorizTwoFingerScroll"); - m_supported.removeAll("VertTwoFingerScroll"); - m_supported.removeAll("TwoFingerTapButton"); - } - - if (!cap[TouchpadThreeFingerDetect]) { - m_supported.removeAll("ThreeFingerTapButton"); - } - - if (!cap[TouchpadPressureDetect]) { - m_supported.removeAll("FingerHigh"); - m_supported.removeAll("FingerLow"); - - m_supported.removeAll("PalmMinZ"); - m_supported.removeAll("PressureMotionMinZ"); - m_supported.removeAll("PressureMotionMinFactor"); - m_supported.removeAll("PressureMotionMaxZ"); - m_supported.removeAll("PressureMotionMaxFactor"); - m_supported.removeAll("EmulateTwoFingerMinZ"); - } - - if (!cap[TouchpadPalmDetect]) { - m_supported.removeAll("PalmDetect"); - m_supported.removeAll("PalmMinWidth"); - m_supported.removeAll("PalmMinZ"); - m_supported.removeAll("EmulateTwoFingerMinW"); - } - - for (QMap::Iterator i = m_negate.begin(); i != m_negate.end(); ++i) { - if (!m_supported.contains(i.key())) { - m_supported.removeAll(i.value()); - } - } - - m_paramList = synapticsProperties; -} - -void SynapticsTouchpad::setTouchpadOff(int touchpadOff) -{ - PropertyInfo off(m_display, m_deviceId, m_touchpadOffAtom.atom(), 0); - if (off.b && *(off.b) != touchpadOff) { - *(off.b) = touchpadOff; - off.set(); - } - - flush(); -} - -int SynapticsTouchpad::touchpadOff() -{ - PropertyInfo off(m_display, m_deviceId, m_touchpadOffAtom.atom(), 0); - return off.value(0).toInt(); -} - -XcbAtom &SynapticsTouchpad::touchpadOffAtom() -{ - return m_touchpadOffAtom; -} - -double SynapticsTouchpad::getPropertyScale(const QString &name) const -{ - if (m_scaleByResX.contains(name) && m_scaleByResY.contains(name)) { - return std::sqrt(static_cast(m_resX) * m_resX + static_cast(m_resY) * m_resY); - } else if (m_scaleByResX.contains(name)) { - return m_resX; - } else if (m_scaleByResY.contains(name)) { - return m_resY; - } else if (m_toRadians.contains(name)) { - return M_PI_4 / 45.0; - } - return 1.0; -} diff --git a/settings-daemon/touchpad/x11/synapticstouchpad.h b/settings-daemon/touchpad/x11/synapticstouchpad.h deleted file mode 100644 index c503ce1..0000000 --- a/settings-daemon/touchpad/x11/synapticstouchpad.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - SPDX-FileCopyrightText: 2015 Weng Xuetian - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef SYNAPTICSTOUCHPAD_H -#define SYNAPTICSTOUCHPAD_H - -#include "xcbatom.h" -#include "xlibtouchpad.h" - -class SynapticsTouchpad : public QObject, public XlibTouchpad -{ - Q_OBJECT - -public: - SynapticsTouchpad(Display *display, int deviceId); - - void setTouchpadOff(int touchpadOff) override; - int touchpadOff() override; - - XcbAtom &touchpadOffAtom() override; - -protected: - double getPropertyScale(const QString &name) const override; - -private: - XcbAtom m_capsAtom, m_touchpadOffAtom; - int m_resX, m_resY; - QStringList m_scaleByResX, m_scaleByResY, m_toRadians; -}; - -#endif // SYNAPTICSTOUCHPAD_H diff --git a/settings-daemon/touchpad/x11/xcbatom.cpp b/settings-daemon/touchpad/x11/xcbatom.cpp deleted file mode 100644 index c48f9d2..0000000 --- a/settings-daemon/touchpad/x11/xcbatom.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013 Alexander Mezin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#include "xcbatom.h" - -#include -#include - -XcbAtom::XcbAtom() - : m_connection(nullptr) - , m_reply(nullptr) - , m_fetched(false) -{ -} - -XcbAtom::XcbAtom(xcb_connection_t *c, const char *name, bool onlyIfExists) - : m_reply(nullptr) - , m_fetched(false) -{ - intern(c, name, onlyIfExists); -} - -void XcbAtom::intern(xcb_connection_t *c, const char *name, bool onlyIfExists) -{ - m_connection = c; - m_cookie = xcb_intern_atom(c, onlyIfExists, std::strlen(name), name); -} - -XcbAtom::~XcbAtom() -{ - std::free(m_reply); -} - -xcb_atom_t XcbAtom::atom() -{ - if (!m_fetched) { - m_fetched = true; - m_reply = xcb_intern_atom_reply(m_connection, m_cookie, nullptr); - } - if (m_reply) { - return m_reply->atom; - } else { - return 0; - } -} diff --git a/settings-daemon/touchpad/x11/xcbatom.h b/settings-daemon/touchpad/x11/xcbatom.h deleted file mode 100644 index e3a8914..0000000 --- a/settings-daemon/touchpad/x11/xcbatom.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013 Alexander Mezin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef XCBATOM_H -#define XCBATOM_H - -#include - -class XcbAtom -{ -public: - XcbAtom(); - XcbAtom(xcb_connection_t *, const char *name, bool onlyIfExists = true); - ~XcbAtom(); - - void intern(xcb_connection_t *, const char *name, bool onlyIfExists = true); - xcb_atom_t atom(); - operator xcb_atom_t() - { - return atom(); - } - -private: - XcbAtom(const XcbAtom &); - XcbAtom &operator=(const XcbAtom &); - - xcb_connection_t *m_connection; - xcb_intern_atom_cookie_t m_cookie; - xcb_intern_atom_reply_t *m_reply; - bool m_fetched; -}; - -#endif // XCBATOM_H diff --git a/settings-daemon/touchpad/x11/xlibbackend.cpp b/settings-daemon/touchpad/x11/xlibbackend.cpp deleted file mode 100644 index e558edd..0000000 --- a/settings-daemon/touchpad/x11/xlibbackend.cpp +++ /dev/null @@ -1,425 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013 Alexander Mezin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#include -#include - -#include - -#include - -// Includes are ordered this way because of #defines in Xorg's headers -#include "xlibbackend.h" // krazy:exclude=includes -#include "xlibnotifications.h" // krazy:exclude=includes -#include "xrecordkeyboardmonitor.h" // krazy:exclude=includes - -#include -#include -#include -#include - -#include -#include - -struct DeviceListDeleter { - static void cleanup(XDeviceInfo *p) - { - if (p) { - XFreeDeviceList(p); - } - } -}; - -void XlibBackend::XDisplayCleanup::cleanup(Display *p) -{ - if (p) { - XCloseDisplay(p); - } -} - -XlibBackend *XlibBackend::initialize(QObject *parent) -{ - XlibBackend *backend = new XlibBackend(parent); - if (!backend->m_display) { - delete backend; - return nullptr; - } - return backend; -} - -XlibBackend::~XlibBackend() -{ -} - -XlibBackend::XlibBackend(QObject *parent) - : QObject(parent) - , m_display(XOpenDisplay(nullptr)) - , m_connection(nullptr) -{ - if (m_display) { - m_connection = XGetXCBConnection(m_display.data()); - } - - if (!m_connection) { - m_errorString = "Cannot connect to X server"; - return; - } - - m_mouseAtom.intern(m_connection, XI_MOUSE); - m_keyboardAtom.intern(m_connection, XI_KEYBOARD); - m_touchpadAtom.intern(m_connection, XI_TOUCHPAD); - m_enabledAtom.intern(m_connection, XI_PROP_ENABLED); - - m_synapticsIdentifierAtom.intern(m_connection, SYNAPTICS_PROP_CAPABILITIES); - m_libinputIdentifierAtom.intern(m_connection, "libinput Send Events Modes Available"); - - m_device.reset(findTouchpad()); - if (!m_device) { - m_errorString = "No touchpad found"; - } -} - -XlibTouchpad *XlibBackend::findTouchpad() -{ - int nDevices = 0; - QScopedPointer deviceInfo(XListInputDevices(m_display.data(), &nDevices)); - - for (XDeviceInfo *info = deviceInfo.data(); info < deviceInfo.data() + nDevices; info++) { - // Make sure device is touchpad - if (info->type != m_touchpadAtom.atom()) { - continue; - } - int nProperties = 0; - QSharedPointer properties(XIListProperties(m_display.data(), info->id, &nProperties), XDeleter); - - Atom *atom = properties.data(), *atomEnd = properties.data() + nProperties; - for (; atom != atomEnd; atom++) { - - if (*atom == m_libinputIdentifierAtom.atom()) { - // setMode(TouchpadInputBackendMode::XLibinput); - return new LibinputTouchpad(m_display.data(), info->id); - } - - if (*atom == m_synapticsIdentifierAtom.atom()) { - // setMode(TouchpadInputBackendMode::XSynaptics); - return new SynapticsTouchpad(m_display.data(), info->id); - } - } - } - - return nullptr; -} - -bool XlibBackend::applyConfig(const QVariantHash &p) -{ - if (!m_device) { - return false; - } - - bool success = m_device->applyConfig(p); - if (!success) { - m_errorString = "Cannot apply touchpad configuration"; - } - - return success; -} - -bool XlibBackend::applyConfig() -{ - if (!m_device) { - return false; - } - - bool success = m_device->applyConfig(); - if (!success) { - m_errorString = "Cannot apply touchpad configuration"; - } - - return success; -} - -bool XlibBackend::getConfig(QVariantHash &p) -{ - if (!m_device) { - return false; - } - - bool success = m_device->getConfig(p); - if (!success) { - m_errorString = "Cannot read touchpad configuration"; - } - return success; -} - -bool XlibBackend::getConfig() -{ - if (!m_device) { - return false; - } - - bool success = m_device->getConfig(); - if (!success) { - m_errorString = "Cannot read touchpad configuration"; - } - return success; -} - -bool XlibBackend::getDefaultConfig() -{ - if (!m_device) { - return false; - } - - bool success = m_device->getDefaultConfig(); - if (!success) { - m_errorString = "Cannot read default touchpad configuration"; - } - return success; -} - -bool XlibBackend::isChangedConfig() const -{ - if (!m_device) { - return false; - } - - return m_device->isChangedConfig(); -} - -void XlibBackend::setTouchpadEnabled(bool enable) -{ - if (!m_device) { - return; - } - - m_device->setEnabled(enable); - - // FIXME? This should not be needed, m_notifications should trigger - // a propertyChanged signal when we enable/disable the touchpad, - // that will Q_EMIT touchpadStateChanged, but for some reason - // XlibNotifications is not getting the property change events - // so we just Q_EMIT touchpadStateChanged from here as a workaround - Q_EMIT touchpadStateChanged(); -} - -bool XlibBackend::tapToClick() -{ - LibinputTouchpad *object = dynamic_cast(m_device.data()); - - if (!object) - return false; - - return object->isTapToClick(); -} - -void XlibBackend::setTapToClick(bool enabled) -{ - LibinputTouchpad *object = dynamic_cast(m_device.data()); - - if (!object) - return; - - object->setTapToClick(enabled); -} - -bool XlibBackend::naturalScroll() -{ - LibinputTouchpad *object = dynamic_cast(m_device.data()); - - if (!object) - return false; - - return object->isNaturalScroll(); -} - -void XlibBackend::setNaturalScroll(bool value) -{ - LibinputTouchpad *object = dynamic_cast(m_device.data()); - - if (!object) - return; - - object->setNaturalScroll(value); -} - -qreal XlibBackend::pointerAcceleration() -{ - LibinputTouchpad *object = dynamic_cast(m_device.data()); - - if (!object) - return 1; - - return object->pointerAcceleration(); -} - -void XlibBackend::setPointerAcceleration(qreal value) -{ - LibinputTouchpad *object = dynamic_cast(m_device.data()); - - if (!object) - return; - - object->setPointerAcceleration(value); -} - -void XlibBackend::setTouchpadOff(XlibBackend::TouchpadOffState state) -{ - if (!m_device) { - return; - } - - int touchpadOff = 0; - switch (state) { - case TouchpadEnabled: - touchpadOff = 0; - break; - case TouchpadFullyDisabled: - touchpadOff = 1; - break; - case TouchpadTapAndScrollDisabled: - touchpadOff = 2; - break; - default: - qCritical() << "Unknown TouchpadOffState" << state; - return; - } - - m_device->setTouchpadOff(touchpadOff); -} - -bool XlibBackend::isTouchpadAvailable() -{ - return !m_device.isNull(); -} - -bool XlibBackend::isTouchpadEnabled() -{ - if (!m_device) { - return false; - } - - return m_device->enabled(); -} - -XlibBackend::TouchpadOffState XlibBackend::getTouchpadOff() -{ - if (!m_device) { - return TouchpadFullyDisabled; - } - int value = m_device->touchpadOff(); - switch (value) { - case 0: - return TouchpadEnabled; - case 1: - return TouchpadFullyDisabled; - case 2: - return TouchpadTapAndScrollDisabled; - default: - qCritical() << "Unknown TouchpadOff value" << value; - return TouchpadFullyDisabled; - } -} - -void XlibBackend::touchpadDetached() -{ - qWarning() << "Touchpad detached"; - m_device.reset(); - Q_EMIT touchpadReset(); -} - -void XlibBackend::devicePlugged(int device) -{ - if (!m_device) { - m_device.reset(findTouchpad()); - if (m_device) { - qWarning() << "Touchpad reset"; - m_notifications.reset(); - watchForEvents(!m_keyboard.isNull()); - Q_EMIT touchpadReset(); - } - } - if (!m_device || device != m_device->deviceId()) { - Q_EMIT mousesChanged(); - } -} - -void XlibBackend::propertyChanged(xcb_atom_t prop) -{ - if ((m_device && prop == m_device->touchpadOffAtom().atom()) || prop == m_enabledAtom.atom()) { - Q_EMIT touchpadStateChanged(); - } -} - -QStringList XlibBackend::listMouses(const QStringList &blacklist) -{ - int nDevices = 0; - QScopedPointer info(XListInputDevices(m_display.data(), &nDevices)); - QStringList list; - for (XDeviceInfo *i = info.data(); i != info.data() + nDevices; i++) { - if (m_device && i->id == static_cast(m_device->deviceId())) { - continue; - } - if (i->use != IsXExtensionPointer && i->use != IsXPointer) { - continue; - } - // type = KEYBOARD && use = Pointer means usb receiver for both keyboard - // and mouse - if (i->type != m_mouseAtom.atom() && i->type != m_keyboardAtom.atom()) { - continue; - } - QString name(i->name); - if (blacklist.contains(name, Qt::CaseInsensitive)) { - continue; - } - PropertyInfo enabled(m_display.data(), i->id, m_enabledAtom.atom(), 0); - if (enabled.value(0) == false) { - continue; - } - list.append(name); - } - - return list; -} - -QVector XlibBackend::getDevices() const -{ - QVector touchpads; - - LibinputTouchpad *libinputtouchpad = dynamic_cast(m_device.data()); - if (libinputtouchpad) { - touchpads.push_back(libinputtouchpad); - } - - SynapticsTouchpad *synaptics = dynamic_cast(m_device.data()); - if (synaptics) { - touchpads.push_back(synaptics); - } - - return touchpads; -} - -void XlibBackend::watchForEvents(bool keyboard) -{ - if (!m_notifications) { - m_notifications.reset(new XlibNotifications(m_display.data(), m_device ? m_device->deviceId() : XIAllDevices)); - connect(m_notifications.data(), SIGNAL(devicePlugged(int)), SLOT(devicePlugged(int))); - connect(m_notifications.data(), SIGNAL(touchpadDetached()), SLOT(touchpadDetached())); - connect(m_notifications.data(), SIGNAL(propertyChanged(xcb_atom_t)), SLOT(propertyChanged(xcb_atom_t))); - } - - if (keyboard == !m_keyboard.isNull()) { - return; - } - - if (!keyboard) { - m_keyboard.reset(); - return; - } - - m_keyboard.reset(new XRecordKeyboardMonitor(m_display.data())); - connect(m_keyboard.data(), SIGNAL(keyboardActivityStarted()), SIGNAL(keyboardActivityStarted())); - connect(m_keyboard.data(), SIGNAL(keyboardActivityFinished()), SIGNAL(keyboardActivityFinished())); -} diff --git a/settings-daemon/touchpad/x11/xlibbackend.h b/settings-daemon/touchpad/x11/xlibbackend.h deleted file mode 100644 index 0d684c9..0000000 --- a/settings-daemon/touchpad/x11/xlibbackend.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013 Alexander Mezin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef XLIBBACKEND_H -#define XLIBBACKEND_H - -#include -#include -#include -#include -#include -#include - -#include "libinputtouchpad.h" -#include "synapticstouchpad.h" -#include "xlibtouchpad.h" - -#include - -#include "propertyinfo.h" -#include "xcbatom.h" - -class XlibTouchpad; -class XlibNotifications; -class XRecordKeyboardMonitor; - -class XlibBackend : public QObject -{ - Q_OBJECT - - Q_PROPERTY(int touchpadCount READ touchpadCount CONSTANT) - -public: - enum TouchpadOffState { - TouchpadEnabled, - TouchpadTapAndScrollDisabled, - TouchpadFullyDisabled, - }; - - static XlibBackend *initialize(QObject *parent = nullptr); - ~XlibBackend(); - - bool applyConfig(const QVariantHash &); - bool applyConfig(); - bool getConfig(QVariantHash &); - bool getConfig(); - bool getDefaultConfig(); - bool isChangedConfig() const; - QStringList supportedParameters() const - { - return m_device ? m_device->supportedParameters() : QStringList(); - } - QString errorString() const - { - return m_errorString; - } - int touchpadCount() const - { - return m_device ? 1 : 0; - } - - void setTouchpadOff(TouchpadOffState); - TouchpadOffState getTouchpadOff(); - - bool isTouchpadAvailable(); - bool isTouchpadEnabled(); - void setTouchpadEnabled(bool); - - bool tapToClick(); - void setTapToClick(bool enabled); - - bool naturalScroll(); - void setNaturalScroll(bool value); - - qreal pointerAcceleration(); - void setPointerAcceleration(qreal value); - - void watchForEvents(bool keyboard); - - QStringList listMouses(const QStringList &blacklist); - QVector getDevices() const; - -signals: - void touchpadStateChanged(); - void mousesChanged(); - void touchpadReset(); - void keyboardActivityStarted(); - void keyboardActivityFinished(); - - void touchpadAdded(bool success); - void touchpadRemoved(int index); - -private Q_SLOTS: - void propertyChanged(xcb_atom_t); - void touchpadDetached(); - void devicePlugged(int); - -protected: - explicit XlibBackend(QObject *parent); - - struct XDisplayCleanup { - static void cleanup(Display *); - }; - - QScopedPointer m_display; - xcb_connection_t *m_connection; - - XcbAtom m_enabledAtom, m_mouseAtom, m_keyboardAtom, m_touchpadAtom; - XcbAtom m_synapticsIdentifierAtom; - XcbAtom m_libinputIdentifierAtom; - - XlibTouchpad *findTouchpad(); - QScopedPointer m_device; - - QString m_errorString; - QScopedPointer m_notifications; - QScopedPointer m_keyboard; -}; - -#endif // XLIBBACKEND_H diff --git a/settings-daemon/touchpad/x11/xlibnotifications.cpp b/settings-daemon/touchpad/x11/xlibnotifications.cpp deleted file mode 100644 index 13037c2..0000000 --- a/settings-daemon/touchpad/x11/xlibnotifications.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013 Alexander Mezin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#include "xlibnotifications.h" - -#include - -#include -#include -#include -#include - -XlibNotifications::XlibNotifications(Display *display, int device) - : m_display(display) - , m_device(device) -{ - m_connection = XGetXCBConnection(display); - - m_notifier = new QSocketNotifier(xcb_get_file_descriptor(m_connection), QSocketNotifier::Read, this); - - xcb_query_extension_cookie_t inputExtCookie = xcb_query_extension(m_connection, std::strlen(INAME), INAME); - QScopedPointer inputExt(xcb_query_extension_reply(m_connection, inputExtCookie, nullptr)); - if (!inputExt) { - return; - } - m_inputOpcode = inputExt->major_opcode; - - const xcb_setup_t *setup = xcb_get_setup(m_connection); - xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); - xcb_screen_t *screen = iter.data; - - m_inputWindow = xcb_generate_id(m_connection); - xcb_create_window(m_connection, 0, m_inputWindow, screen->root, 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY, 0, 0, nullptr); - xcb_flush(m_connection); - - XIEventMask masks[2]; - - unsigned char touchpadMask[] = {0, 0, 0, 0}; - masks[0].deviceid = device; - masks[0].mask = touchpadMask; - masks[0].mask_len = sizeof(touchpadMask); - XISetMask(touchpadMask, XI_PropertyEvent); - - unsigned char allMask[] = {0, 0, 0, 0}; - masks[1].deviceid = XIAllDevices; - masks[1].mask = allMask; - masks[1].mask_len = sizeof(allMask); - XISetMask(allMask, XI_HierarchyChanged); - - XISelectEvents(display, XDefaultRootWindow(display), masks, sizeof(masks) / sizeof(XIEventMask)); - XFlush(display); - - connect(m_notifier, SIGNAL(activated(int)), SLOT(processEvents())); - m_notifier->setEnabled(true); -} - -void XlibNotifications::processEvents() -{ - while (XPending(m_display)) { - XEvent event; - XNextEvent(m_display, &event); - processEvent(&event); - } -} - -struct XEventDataDeleter { - XEventDataDeleter(Display *display, XGenericEventCookie *cookie) - : m_display(display) - , m_cookie(cookie) - { - XGetEventData(m_display, m_cookie); - } - - ~XEventDataDeleter() - { - if (m_cookie->data) { - XFreeEventData(m_display, m_cookie); - } - } - - Display *m_display; - XGenericEventCookie *m_cookie; -}; - -void XlibNotifications::processEvent(XEvent *event) -{ - if (event->xcookie.type != GenericEvent) { - return; - } - if (event->xcookie.extension != m_inputOpcode) { - return; - } - - if (event->xcookie.evtype == XI_PropertyEvent) { - XEventDataDeleter helper(m_display, &event->xcookie); - if (!event->xcookie.data) { - return; - } - - XIPropertyEvent *propEvent = reinterpret_cast(event->xcookie.data); - Q_EMIT propertyChanged(propEvent->property); - } else if (event->xcookie.evtype == XI_HierarchyChanged) { - XEventDataDeleter helper(m_display, &event->xcookie); - if (!event->xcookie.data) { - return; - } - - XIHierarchyEvent *hierarchyEvent = reinterpret_cast(event->xcookie.data); - for (uint16_t i = 0; i < hierarchyEvent->num_info; i++) { - if (hierarchyEvent->info[i].deviceid == m_device) { - if (hierarchyEvent->info[i].flags & XISlaveRemoved) { - Q_EMIT touchpadDetached(); - return; - } - } - if (hierarchyEvent->info[i].use != XISlavePointer) { - continue; - } - if (hierarchyEvent->info[i].flags & (XIDeviceEnabled | XIDeviceDisabled)) { - Q_EMIT devicePlugged(hierarchyEvent->info[i].deviceid); - } - } - } -} - -XlibNotifications::~XlibNotifications() -{ - xcb_destroy_window(m_connection, m_inputWindow); - xcb_flush(m_connection); -} - -#include "moc_xlibnotifications.cpp" diff --git a/settings-daemon/touchpad/x11/xlibnotifications.h b/settings-daemon/touchpad/x11/xlibnotifications.h deleted file mode 100644 index 5ca6f1d..0000000 --- a/settings-daemon/touchpad/x11/xlibnotifications.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013 Alexander Mezin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef XLIBNOTIFICATIONS_H -#define XLIBNOTIFICATIONS_H - -#include - -#include -#include - -class XlibNotifications : public QObject -{ - Q_OBJECT -public: - XlibNotifications(Display *display, int device); - ~XlibNotifications(); - -Q_SIGNALS: - void propertyChanged(xcb_atom_t); - void devicePlugged(int); - void touchpadDetached(); - -private Q_SLOTS: - void processEvents(); - -private: - void processEvent(XEvent *); - - Display *m_display; - xcb_connection_t *m_connection; - QSocketNotifier *m_notifier; - xcb_window_t m_inputWindow; - uint8_t m_inputOpcode; - int m_device; -}; - -#endif // XLIBNOTIFICATIONS_H diff --git a/settings-daemon/touchpad/x11/xlibtouchpad.cpp b/settings-daemon/touchpad/x11/xlibtouchpad.cpp deleted file mode 100644 index 7581c9a..0000000 --- a/settings-daemon/touchpad/x11/xlibtouchpad.cpp +++ /dev/null @@ -1,257 +0,0 @@ -#include - -#include "xlibtouchpad.h" -#include -#include -#include -#include - -static QVariant negateVariant(const QVariant &value) -{ - if (value.type() == QVariant::Double) { - return QVariant(-value.toDouble()); - } else if (value.type() == QVariant::Int) { - return QVariant(-value.toInt()); - } - return value; -} - -XlibTouchpad::XlibTouchpad(Display *display, int deviceId) - : m_display(display) - , m_connection(XGetXCBConnection(display)) - , m_deviceId(deviceId) -{ - m_floatType.intern(m_connection, "FLOAT"); - m_enabledAtom.intern(m_connection, XI_PROP_ENABLED); -} - -bool XlibTouchpad::applyConfig(const QVariantHash &p) -{ - m_props.clear(); - - bool error = false; - for (const QString &name : qAsConst(m_supported)) { - QVariantHash::ConstIterator i = p.find(name); - if (i == p.end()) { - continue; - } - const Parameter *par = findParameter(name); - if (par) { - QVariant value(i.value()); - - double k = getPropertyScale(name); - if (k != 1.0) { - bool ok = false; - value = QVariant(value.toDouble(&ok) * k); - if (!ok) { - error = true; - continue; - } - } - - if (m_negate.contains(name)) { - QVariantHash::ConstIterator i = p.find(m_negate[name]); - if (i != p.end() && i.value().toBool()) { - value = negateVariant(value); - } - } - - if (name == "CoastingSpeed") { - QVariantHash::ConstIterator coastingEnabled = p.find("Coasting"); - if (coastingEnabled != p.end() && !coastingEnabled.value().toBool()) { - value = QVariant(0); - } - } - - if (!setParameter(par, value)) { - error = true; - } - } - } - - flush(); - - return !error; -} - -bool XlibTouchpad::getConfig(QVariantHash &p) -{ - if (m_supported.isEmpty()) { - return false; - } - - m_props.clear(); - - bool error = false; - for (const QString &name : qAsConst(m_supported)) { - const Parameter *par = findParameter(name); - if (!par) { - continue; - } - - QVariant value(getParameter(par)); - if (!value.isValid()) { - error = true; - continue; - } - - double k = getPropertyScale(name); - if (k != 1.0) { - bool ok = false; - value = QVariant(value.toDouble(&ok) / k); - if (!ok) { - error = true; - continue; - } - } - - if (m_negate.contains(name)) { - bool negative = value.toDouble() < 0.0; - p[m_negate[name]] = QVariant(negative); - if (negative) { - value = negateVariant(value); - } - } - - if (name == "CoastingSpeed") { - bool coasting = value.toDouble() != 0.0; - p["Coasting"] = QVariant(coasting); - if (!coasting) { - continue; - } - } - - p[name] = value; - } - - return !error; -} - -void XlibTouchpad::loadSupportedProperties(const Parameter *props) -{ - m_paramList = props; - for (const Parameter *param = props; param->name; param++) { - QLatin1String name(param->prop_name); - - if (!m_atoms.contains(name)) { - m_atoms.insert(name, QSharedPointer(new XcbAtom(m_connection, param->prop_name))); - } - } - - for (const Parameter *p = props; p->name; p++) { - if (getParameter(p).isValid()) { - m_supported.append(p->name); - } - } -} - -QVariant XlibTouchpad::getParameter(const Parameter *par) -{ - PropertyInfo *p = getDevProperty(QLatin1String(par->prop_name)); - if (!p || par->prop_offset >= p->nitems) { - return QVariant(); - } - - return p->value(par->prop_offset); -} - -void XlibTouchpad::flush() -{ - for (const QLatin1String &name : qAsConst(m_changed)) { - m_props[name].set(); - } - m_changed.clear(); - - XFlush(m_display); -} - -double XlibTouchpad::getPropertyScale(const QString &name) const -{ - Q_UNUSED(name); - return 1.0; -} - -PropertyInfo *XlibTouchpad::getDevProperty(const QLatin1String &propName) -{ - if (m_props.contains(propName)) { - return &m_props[propName]; - } - - if (!m_atoms.contains(propName) || !m_atoms[propName]) { - return nullptr; - } - - xcb_atom_t prop = m_atoms[propName]->atom(); - if (!prop) { - return nullptr; - } - - PropertyInfo p(m_display, m_deviceId, prop, m_floatType.atom()); - if (!p.b && !p.f && !p.i) { - return nullptr; - } - return &m_props.insert(propName, p).value(); -} - -bool XlibTouchpad::setParameter(const Parameter *par, const QVariant &value) -{ - QLatin1String propName(par->prop_name); - PropertyInfo *p = getDevProperty(propName); - if (!p || par->prop_offset >= p->nitems) { - return false; - } - - QVariant converted(value); - QVariant::Type convType = QVariant::Int; - if (p->f) { - convType = QVariant::Double; - } else if (value.type() == QVariant::Double) { - converted = QVariant(qRound(static_cast(value.toDouble()))); - } - - if (!converted.convert(convType)) { - return false; - } - - if (converted == p->value(par->prop_offset)) { - return true; - } - - if (p->b) { - p->b[par->prop_offset] = static_cast(converted.toInt()); - } else if (p->i) { - p->i[par->prop_offset] = converted.toInt(); - } else if (p->f) { - p->f[par->prop_offset] = converted.toDouble(); - } - - m_changed.insert(propName); - return true; -} - -void XlibTouchpad::setEnabled(bool enable) -{ - PropertyInfo enabled(m_display, m_deviceId, m_enabledAtom.atom(), 0); - if (enabled.b && *(enabled.b) != enable) { - *(enabled.b) = enable; - enabled.set(); - } - - flush(); -} - -bool XlibTouchpad::enabled() -{ - PropertyInfo enabled(m_display, m_deviceId, m_enabledAtom.atom(), 0); - return enabled.value(0).toBool(); -} - -const Parameter *XlibTouchpad::findParameter(const QString &name) -{ - for (const Parameter *par = m_paramList; par->name; par++) { - if (name == par->name) { - return par; - } - } - return nullptr; -} diff --git a/settings-daemon/touchpad/x11/xlibtouchpad.h b/settings-daemon/touchpad/x11/xlibtouchpad.h deleted file mode 100644 index f20bb66..0000000 --- a/settings-daemon/touchpad/x11/xlibtouchpad.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - SPDX-FileCopyrightText: 2015 Weng Xuetian - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef XLIBTOUCHPAD_H -#define XLIBTOUCHPAD_H - -#include -#include -#include - -#include "propertyinfo.h" -#include "xcbatom.h" -#include - -enum ParaType { - PT_INT, - PT_BOOL, - PT_DOUBLE, -}; - -struct Parameter { - const char *name; /* Name of parameter */ - enum ParaType type; /* Type of parameter */ - double min_val; /* Minimum allowed value */ - double max_val; /* Maximum allowed value */ - const char *prop_name; /* Property name */ - int prop_format; /* Property format (0 for floats) */ - unsigned prop_offset; /* Offset inside property */ -}; - -class XlibTouchpad -{ -public: - XlibTouchpad(Display *display, int deviceId); - virtual ~XlibTouchpad() - { - } - - int deviceId() - { - return m_deviceId; - } - const QStringList &supportedParameters() const - { - return m_supported; - } - bool applyConfig(const QVariantHash &p); - bool getConfig(QVariantHash &p); - virtual bool getConfig() - { - return false; - } - virtual bool applyConfig() - { - return false; - } - virtual bool getDefaultConfig() - { - return false; - } - virtual bool isChangedConfig() - { - return false; - } - void setEnabled(bool enable); - bool enabled(); - virtual void setTouchpadOff(int /*touchpadOff*/) - { - } - virtual int touchpadOff() = 0; - - virtual XcbAtom &touchpadOffAtom() = 0; - -protected: - void loadSupportedProperties(const Parameter *props); - bool setParameter(const struct Parameter *, const QVariant &); - QVariant getParameter(const struct Parameter *); - struct PropertyInfo *getDevProperty(const QLatin1String &propName); - void flush(); - virtual double getPropertyScale(const QString &name) const; - const Parameter *findParameter(const QString &name); - - Display *m_display; - xcb_connection_t *m_connection; - int m_deviceId; - - XcbAtom m_floatType, m_enabledAtom; - - QMap> m_atoms; - - QMap m_negate; - QMap m_props; - QSet m_changed; - QStringList m_supported; - const struct Parameter *m_paramList; -}; - -#endif diff --git a/settings-daemon/touchpad/x11/xrecordkeyboardmonitor.cpp b/settings-daemon/touchpad/x11/xrecordkeyboardmonitor.cpp deleted file mode 100644 index c9fe99b..0000000 --- a/settings-daemon/touchpad/x11/xrecordkeyboardmonitor.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013 Alexander Mezin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#include "xrecordkeyboardmonitor.h" - -#include -#include - -#include - -#include -#include - -XRecordKeyboardMonitor::XRecordKeyboardMonitor(Display *display) - : m_connection(xcb_connect(XDisplayString(display), nullptr)) - , m_modifiersPressed(0) - , m_keysPressed(0) -{ - if (!m_connection) { - return; - } - - xcb_get_modifier_mapping_cookie_t modmapCookie = xcb_get_modifier_mapping(m_connection); - - m_context = xcb_generate_id(m_connection); - xcb_record_range_t range; - memset(&range, 0, sizeof(range)); - range.device_events.first = XCB_KEY_PRESS; - range.device_events.last = XCB_KEY_RELEASE; - xcb_record_client_spec_t cs = XCB_RECORD_CS_ALL_CLIENTS; - xcb_record_create_context(m_connection, m_context, 0, 1, 1, &cs, &range); - xcb_flush(m_connection); - - QScopedPointer modmap(xcb_get_modifier_mapping_reply(m_connection, modmapCookie, nullptr)); - if (!modmap) { - return; - } - - int nModifiers = xcb_get_modifier_mapping_keycodes_length(modmap.data()); - xcb_keycode_t *modifiers = xcb_get_modifier_mapping_keycodes(modmap.data()); - m_modifier.fill(false, std::numeric_limits::max() + 1); - for (xcb_keycode_t *i = modifiers; i < modifiers + nModifiers; i++) { - m_modifier[*i] = true; - } - m_ignore.fill(false, std::numeric_limits::max() + 1); - for (xcb_keycode_t *i = modifiers; i < modifiers + modmap->keycodes_per_modifier; i++) { - m_ignore[*i] = true; - } - m_pressed.fill(false, std::numeric_limits::max() + 1); - - m_cookie = xcb_record_enable_context(m_connection, m_context); - xcb_flush(m_connection); - - m_notifier = new QSocketNotifier(xcb_get_file_descriptor(m_connection), QSocketNotifier::Read, this); - connect(m_notifier, &QSocketNotifier::activated, this, &XRecordKeyboardMonitor::processNextReply); - m_notifier->setEnabled(true); -} - -XRecordKeyboardMonitor::~XRecordKeyboardMonitor() -{ - if (!m_connection) { - return; - } - - xcb_record_disable_context(m_connection, m_context); - xcb_record_free_context(m_connection, m_context); - xcb_disconnect(m_connection); -} - -void XRecordKeyboardMonitor::processNextReply() -{ - xcb_generic_event_t *event; - while ((event = xcb_poll_for_event(m_connection))) { - std::free(event); - } - - void *reply = nullptr; - xcb_generic_error_t *error = nullptr; - while (m_cookie.sequence && xcb_poll_for_reply(m_connection, m_cookie.sequence, &reply, &error)) { - // xcb_poll_for_reply may set both reply and error to null if connection has error. - // break if xcb_connection has error, no point to continue anyway. - if (xcb_connection_has_error(m_connection)) { - break; - } - - if (error) { - std::free(error); - break; - } - - if (!reply) { - continue; - } - - QScopedPointer data(reinterpret_cast(reply)); - process(data.data()); - } -} - -void XRecordKeyboardMonitor::process(xcb_record_enable_context_reply_t *reply) -{ - bool prevActivity = activity(); - - xcb_key_press_event_t *events = reinterpret_cast(xcb_record_enable_context_data(reply)); - int nEvents = xcb_record_enable_context_data_length(reply) / sizeof(xcb_key_press_event_t); - bool wasActivity = prevActivity; - for (xcb_key_press_event_t *e = events; e < events + nEvents; e++) { - if (e->response_type != XCB_KEY_PRESS && e->response_type != XCB_KEY_RELEASE) { - continue; - } - - if (m_ignore[e->detail]) { - continue; - } - - bool pressed = (e->response_type == XCB_KEY_PRESS); - if (m_pressed[e->detail] == pressed) { - continue; - } - m_pressed[e->detail] = pressed; - - int &counter = m_modifier[e->detail] ? m_modifiersPressed : m_keysPressed; - if (pressed) { - counter++; - } else { - counter--; - } - - wasActivity = wasActivity || activity(); - } - - if (!prevActivity && activity()) { - Q_EMIT keyboardActivityStarted(); - } else if (!activity() && wasActivity) { - Q_EMIT keyboardActivityFinished(); - } -} diff --git a/settings-daemon/touchpad/x11/xrecordkeyboardmonitor.h b/settings-daemon/touchpad/x11/xrecordkeyboardmonitor.h deleted file mode 100644 index 028c6f7..0000000 --- a/settings-daemon/touchpad/x11/xrecordkeyboardmonitor.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013 Alexander Mezin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef XRECORDKEYBOARDMONITOR_H -#define XRECORDKEYBOARDMONITOR_H - -#include -#include - -#include - -#include -#include - -class XRecordKeyboardMonitor : public QObject -{ - Q_OBJECT - -public: - XRecordKeyboardMonitor(Display *display); - ~XRecordKeyboardMonitor(); - -Q_SIGNALS: - void keyboardActivityStarted(); - void keyboardActivityFinished(); - -private Q_SLOTS: - void processNextReply(); - -private: - void process(xcb_record_enable_context_reply_t *reply); - bool activity() const - { - return m_keysPressed && !m_modifiersPressed; - } - - QSocketNotifier *m_notifier; - xcb_connection_t *m_connection; - xcb_record_context_t m_context; - xcb_record_enable_context_cookie_t m_cookie; - - QVector m_modifier, m_ignore, m_pressed; - int m_modifiersPressed, m_keysPressed; -}; - -#endif // XRECORDKEYBOARDMONITOR_H diff --git a/shutdown-ui/main.qml b/shutdown-ui/main.qml index 443311a..a548dcc 100644 --- a/shutdown-ui/main.qml +++ b/shutdown-ui/main.qml @@ -32,7 +32,7 @@ ApplicationWindow { height: Screen.height visible: true visibility: Window.FullScreen - flags: Qt.FramelessWindowHint | Qt.X11BypassWindowManagerHint + flags: Qt.FramelessWindowHint id: root function exit() { diff --git a/x11utils.h b/x11utils.h deleted file mode 100644 index a2d5dbc..0000000 --- a/x11utils.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace Cutefish::X11 -{ -inline xcb_window_t rootWindow() -{ - const auto native = qGuiApp ? qGuiApp->nativeInterface() : nullptr; - const auto c = native ? native->connection() : nullptr; - if (!c) - return XCB_WINDOW_NONE; - - const auto *setup = xcb_get_setup(c); - const auto iterator = xcb_setup_roots_iterator(setup); - return iterator.data ? iterator.data->root : XCB_WINDOW_NONE; -} - -inline int screenNumber() -{ - return 0; -} -} diff --git a/xembed-sni-proxy/CMakeLists.txt b/xembed-sni-proxy/CMakeLists.txt deleted file mode 100644 index 9018318..0000000 --- a/xembed-sni-proxy/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -project(cutefish-xembedsniproxy) - -add_definitions(-DQT_NO_CAST_TO_ASCII --DQT_NO_CAST_FROM_ASCII --DQT_NO_URL_CAST_FROM_STRING --DQT_NO_CAST_FROM_BYTEARRAY) - -find_package(X11) -set_package_properties(X11 PROPERTIES DESCRIPTION "X11 libraries" - URL "http://www.x.org" - TYPE OPTIONAL - PURPOSE "Required for building the X11 based workspace") - -if(X11_FOUND) - find_package(XCB MODULE REQUIRED COMPONENTS XCB RANDR) - set_package_properties(XCB PROPERTIES TYPE REQUIRED) - if(NOT X11_SM_FOUND) - message(FATAL_ERROR "\nThe X11 Session Management (SM) development package could not be found.\nPlease install libSM.\n") - endif(NOT X11_SM_FOUND) - - find_package(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Gui) -endif() - -if(X11_FOUND AND XCB_XCB_FOUND) - set(HAVE_X11 1) -endif() - -find_package(XCB - REQUIRED COMPONENTS - XCB - XFIXES - DAMAGE - COMPOSITE - RANDR - SHM - UTIL - IMAGE -) - -find_package(KF6WindowSystem) - -set(XCB_LIBS - XCB::XCB - XCB::XFIXES - XCB::DAMAGE - XCB::COMPOSITE - XCB::RANDR - XCB::SHM - XCB::UTIL - XCB::IMAGE -) - -set(XEMBED_SNI_PROXY_SOURCES - main.cpp - fdoselectionmanager.cpp - snidbus.cpp - sniproxy.cpp - debug.cpp - xtestsender.cpp -) - -qt6_add_dbus_adaptor(DBUS_SOURCES org.kde.StatusNotifierItem.xml - sniproxy.h SNIProxy) -set(statusnotifierwatcher_xml org.kde.StatusNotifierWatcher.xml) -qt6_add_dbus_interface(DBUS_SOURCES ${statusnotifierwatcher_xml} statusnotifierwatcher_interface) - -set_source_files_properties(${DBUS_SOURCES} PROPERTIES SKIP_AUTOGEN ON) - -add_executable(cutefish-xembedsniproxy ${XEMBED_SNI_PROXY_SOURCES} ${DBUS_SOURCES}) -set_package_properties(XCB PROPERTIES TYPE REQUIRED) -target_link_libraries(cutefish-xembedsniproxy - Qt6::Core - Qt6::Gui - Qt6::DBus - KF6::WindowSystem - ${XCB_LIBS} - ${X11_XTest_LIB} -) - -install(TARGETS cutefish-xembedsniproxy DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/xembed-sni-proxy/debug.cpp b/xembed-sni-proxy/debug.cpp deleted file mode 100644 index 4352822..0000000 --- a/xembed-sni-proxy/debug.cpp +++ /dev/null @@ -1,8 +0,0 @@ -/* This file is part of the KDE project - SPDX-FileCopyrightText: 2015 Bhushan Shah - SPDX-License-Identifier: LGPL-2.0-or-later -*/ - -#include "debug.h" - -Q_LOGGING_CATEGORY(SNIPROXY, "com.cutefish.sniproxy", QtWarningMsg) \ No newline at end of file diff --git a/xembed-sni-proxy/debug.h b/xembed-sni-proxy/debug.h deleted file mode 100644 index d31fffa..0000000 --- a/xembed-sni-proxy/debug.h +++ /dev/null @@ -1,12 +0,0 @@ -/* This file is part of the KDE project - SPDX-FileCopyrightText: 2015 Bhushan Shah - SPDX-License-Identifier: LGPL-2.0-or-later -*/ - -#ifndef DEBUG_H -#define DEBUG_H - -#include -Q_DECLARE_LOGGING_CATEGORY(SNIPROXY) - -#endif \ No newline at end of file diff --git a/xembed-sni-proxy/fdoselectionmanager.cpp b/xembed-sni-proxy/fdoselectionmanager.cpp deleted file mode 100644 index 88b2f49..0000000 --- a/xembed-sni-proxy/fdoselectionmanager.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* - Registers as a embed container - SPDX-FileCopyrightText: 2015 David Edmundson - SPDX-FileCopyrightText: 2019 Konrad Materka - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ -#include "fdoselectionmanager.h" - -#include "debug.h" - -#include -#include - -#include - -#include -#include -#include -#include - -#include "sniproxy.h" -#include "xcbutils.h" - -#define SYSTEM_TRAY_REQUEST_DOCK 0 -#define SYSTEM_TRAY_BEGIN_MESSAGE 1 -#define SYSTEM_TRAY_CANCEL_MESSAGE 2 - -FdoSelectionManager::FdoSelectionManager() - : QObject() - , m_selectionOwner(new KSelectionOwner(Xcb::atoms->selectionAtom, -1, this)) -{ - qCDebug(SNIPROXY) << "starting"; - - // we may end up calling QCoreApplication::quit() in this method, at which point we need the event loop running - QTimer::singleShot(0, this, &FdoSelectionManager::init); -} - -FdoSelectionManager::~FdoSelectionManager() -{ - qCDebug(SNIPROXY) << "closing"; - m_selectionOwner->release(); -} - -void FdoSelectionManager::init() -{ - // load damage extension - xcb_connection_t *c = qGuiApp->nativeInterface()->connection(); - xcb_prefetch_extension_data(c, &xcb_damage_id); - const auto *reply = xcb_get_extension_data(c, &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); - } else { - // no XDamage means - qCCritical(SNIPROXY) << "could not load damage extension. Quitting"; - qApp->exit(-1); - } - - qApp->installNativeEventFilter(this); - - connect(m_selectionOwner, &KSelectionOwner::claimedOwnership, this, &FdoSelectionManager::onClaimedOwnership); - connect(m_selectionOwner, &KSelectionOwner::failedToClaimOwnership, this, &FdoSelectionManager::onFailedToClaimOwnership); - connect(m_selectionOwner, &KSelectionOwner::lostOwnership, this, &FdoSelectionManager::onLostOwnership); - m_selectionOwner->claim(false); -} - -bool FdoSelectionManager::addDamageWatch(xcb_window_t client) -{ - qCDebug(SNIPROXY) << "adding damage watch for " << client; - - xcb_connection_t *c = qGuiApp->nativeInterface()->connection(); - const auto attribsCookie = xcb_get_window_attributes_unchecked(c, client); - - const auto damageId = xcb_generate_id(c); - m_damageWatches[client] = damageId; - xcb_damage_create(c, damageId, client, XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY); - - xcb_generic_error_t *error = nullptr; - QScopedPointer attr(xcb_get_window_attributes_reply(c, attribsCookie, &error)); - QScopedPointer getAttrError(error); - uint32_t events = XCB_EVENT_MASK_STRUCTURE_NOTIFY; - if (!attr.isNull()) { - events = events | attr->your_event_mask; - } - // if window is already gone, there is no need to handle it. - if (getAttrError && getAttrError->error_code == XCB_WINDOW) { - return false; - } - // 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)); - // 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; - } - - return true; -} - -bool FdoSelectionManager::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) -{ - Q_UNUSED(result) - - if (eventType != "xcb_generic_event_t") { - return false; - } - - xcb_generic_event_t *ev = static_cast(message); - - const auto responseType = XCB_EVENT_RESPONSE_TYPE(ev); - if (responseType == XCB_CLIENT_MESSAGE) { - const auto ce = reinterpret_cast(ev); - if (ce->type == Xcb::atoms->opcodeAtom) { - switch (ce->data.data32[1]) { - case SYSTEM_TRAY_REQUEST_DOCK: - dock(ce->data.data32[2]); - return true; - } - } - } else if (responseType == XCB_UNMAP_NOTIFY) { - const auto unmappedWId = reinterpret_cast(ev)->window; - if (m_proxies.contains(unmappedWId)) { - undock(unmappedWId); - } - } else if (responseType == XCB_DESTROY_NOTIFY) { - const auto destroyedWId = reinterpret_cast(ev)->window; - if (m_proxies.contains(destroyedWId)) { - undock(destroyedWId); - } - } else if (responseType == m_damageEventBase + XCB_DAMAGE_NOTIFY) { - const auto damagedWId = reinterpret_cast(ev)->drawable; - const auto sniProxy = m_proxies.value(damagedWId); - if (sniProxy) { - sniProxy->update(); - xcb_damage_subtract(qGuiApp->nativeInterface()->connection(), m_damageWatches[damagedWId], XCB_NONE, XCB_NONE); - } - } else if (responseType == XCB_CONFIGURE_REQUEST) { - const auto event = reinterpret_cast(ev); - const auto sniProxy = m_proxies.value(event->window); - if (sniProxy) { - // The embedded window tries to move or resize. Ignore move, handle resize only. - if ((event->value_mask & XCB_CONFIG_WINDOW_WIDTH) || (event->value_mask & XCB_CONFIG_WINDOW_HEIGHT)) { - sniProxy->resizeWindow(event->width, event->height); - } - } - } else if (responseType == XCB_VISIBILITY_NOTIFY) { - const auto event = reinterpret_cast(ev); - // it's possible that something showed our container window, we have to hide it - // workaround for BUG 357443: when KWin is restarted, container window is shown on top - if (event->state == XCB_VISIBILITY_UNOBSCURED) { - for (auto sniProxy : m_proxies.values()) { - sniProxy->hideContainerWindow(event->window); - } - } - } - - return false; -} - -void FdoSelectionManager::dock(xcb_window_t winId) -{ - qCDebug(SNIPROXY) << "trying to dock window " << winId; - - if (m_proxies.contains(winId)) { - return; - } - - if (addDamageWatch(winId)) { - m_proxies[winId] = new SNIProxy(winId, this); - } -} - -void FdoSelectionManager::undock(xcb_window_t winId) -{ - qCDebug(SNIPROXY) << "trying to undock window " << winId; - - if (!m_proxies.contains(winId)) { - return; - } - m_proxies[winId]->deleteLater(); - m_proxies.remove(winId); -} - -void FdoSelectionManager::onClaimedOwnership() -{ - qCDebug(SNIPROXY) << "Manager selection claimed"; - - setSystemTrayVisual(); -} - -void FdoSelectionManager::onFailedToClaimOwnership() -{ - qCWarning(SNIPROXY) << "failed to claim ownership of Systray Manager"; - qApp->exit(-1); -} - -void FdoSelectionManager::onLostOwnership() -{ - qCWarning(SNIPROXY) << "lost ownership of Systray Manager"; - qApp->exit(-1); -} - -void FdoSelectionManager::setSystemTrayVisual() -{ - xcb_connection_t *c = qGuiApp->nativeInterface()->connection(); - auto screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data; - auto trayVisual = screen->root_visual; - xcb_depth_iterator_t depth_iterator = xcb_screen_allowed_depths_iterator(screen); - xcb_depth_t *depth = nullptr; - - while (depth_iterator.rem) { - if (depth_iterator.data->depth == 32) { - depth = depth_iterator.data; - break; - } - xcb_depth_next(&depth_iterator); - } - - if (depth) { - xcb_visualtype_iterator_t visualtype_iterator = xcb_depth_visuals_iterator(depth); - while (visualtype_iterator.rem) { - xcb_visualtype_t *visualtype = visualtype_iterator.data; - if (visualtype->_class == XCB_VISUAL_CLASS_TRUE_COLOR) { - trayVisual = visualtype->visual_id; - break; - } - xcb_visualtype_next(&visualtype_iterator); - } - } - - xcb_change_property(c, XCB_PROP_MODE_REPLACE, m_selectionOwner->ownerWindow(), Xcb::atoms->visualAtom, XCB_ATOM_VISUALID, 32, 1, &trayVisual); -} diff --git a/xembed-sni-proxy/fdoselectionmanager.h b/xembed-sni-proxy/fdoselectionmanager.h deleted file mode 100644 index 96d5519..0000000 --- a/xembed-sni-proxy/fdoselectionmanager.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - Registers as a embed container - SPDX-FileCopyrightText: 2015 David Edmundson - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#pragma once - -#include -#include -#include - -#include - -class KSelectionOwner; -class SNIProxy; - -class FdoSelectionManager : public QObject, public QAbstractNativeEventFilter -{ - Q_OBJECT - -public: - FdoSelectionManager(); - ~FdoSelectionManager() override; - -protected: - bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override; - -private Q_SLOTS: - void onClaimedOwnership(); - void onFailedToClaimOwnership(); - void onLostOwnership(); - -private: - void init(); - bool addDamageWatch(xcb_window_t client); - void dock(xcb_window_t embed_win); - void undock(xcb_window_t client); - void setSystemTrayVisual(); - - uint8_t m_damageEventBase; - - QHash m_damageWatches; - QHash m_proxies; - KSelectionOwner *m_selectionOwner; -}; diff --git a/xembed-sni-proxy/main.cpp b/xembed-sni-proxy/main.cpp deleted file mode 100644 index a95ec36..0000000 --- a/xembed-sni-proxy/main.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - Main - SPDX-FileCopyrightText: 2015 David Edmundson - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#include -#include - -#include "fdoselectionmanager.h" - -#include "debug.h" -#include "snidbus.h" -#include "xcbutils.h" - -#include - -#include - -namespace Xcb -{ -Xcb::Atoms *atoms; -} - -int main(int argc, char **argv) -{ - // the whole point of this is to interact with X, if we are in any other session, force trying to connect to X - // if the QPA can't load xcb, this app is useless anyway. - qputenv("QT_QPA_PLATFORM", "xcb"); - - QGuiApplication::setDesktopSettingsAware(false); - - QGuiApplication app(argc, argv); - - if (!KWindowSystem::isPlatformX11()) { - qFatal("xembed-sni-proxy is only useful XCB. Aborting"); - } - - auto disableSessionManagement = [](QSessionManager &sm) { - sm.setRestartHint(QSessionManager::RestartNever); - }; - QObject::connect(&app, &QGuiApplication::commitDataRequest, disableSessionManagement); - QObject::connect(&app, &QGuiApplication::saveStateRequest, disableSessionManagement); - - app.setQuitOnLastWindowClosed(false); - - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - - Xcb::atoms = new Xcb::Atoms(); - - FdoSelectionManager manager; - - auto rc = app.exec(); - - delete Xcb::atoms; - return rc; -} diff --git a/xembed-sni-proxy/org.kde.StatusNotifierItem.xml b/xembed-sni-proxy/org.kde.StatusNotifierItem.xml deleted file mode 100644 index 0cd7edb..0000000 --- a/xembed-sni-proxy/org.kde.StatusNotifierItem.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/xembed-sni-proxy/org.kde.StatusNotifierWatcher.xml b/xembed-sni-proxy/org.kde.StatusNotifierWatcher.xml deleted file mode 100644 index 2eb1a7a..0000000 --- a/xembed-sni-proxy/org.kde.StatusNotifierWatcher.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/xembed-sni-proxy/snidbus.cpp b/xembed-sni-proxy/snidbus.cpp deleted file mode 100644 index 12caec5..0000000 --- a/xembed-sni-proxy/snidbus.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* - SNI DBus Serialisers - SPDX-FileCopyrightText: 2015 David Edmundson - SPDX-FileCopyrightText: 2009 Marco Martin - - SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL -*/ - -#include "snidbus.h" - -#include -#include - -// mostly copied from KStatusNotiferItemDbus.cpps from knotification - -KDbusImageStruct::KDbusImageStruct() -{ -} - -KDbusImageStruct::KDbusImageStruct(const QImage &image) -{ - width = image.size().width(); - height = image.size().height(); - if (image.format() == QImage::Format_ARGB32) { - data = QByteArray((char *)image.bits(), image.sizeInBytes()); - } else { - QImage image32 = image.convertToFormat(QImage::Format_ARGB32); - data = QByteArray((char *)image32.bits(), image32.sizeInBytes()); - } - - // swap to network byte order if we are little endian - if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { - quint32 *uintBuf = (quint32 *)data.data(); - for (uint i = 0; i < data.size() / sizeof(quint32); ++i) { - *uintBuf = qToBigEndian(*uintBuf); - ++uintBuf; - } - } -} - -// Marshall the ImageStruct data into a D-BUS argument -const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageStruct &icon) -{ - argument.beginStructure(); - argument << icon.width; - argument << icon.height; - argument << icon.data; - argument.endStructure(); - return argument; -} - -// Retrieve the ImageStruct data from the D-BUS argument -const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusImageStruct &icon) -{ - qint32 width; - qint32 height; - QByteArray data; - - argument.beginStructure(); - argument >> width; - argument >> height; - argument >> data; - argument.endStructure(); - - icon.width = width; - icon.height = height; - icon.data = data; - - return argument; -} - -// Marshall the ImageVector data into a D-BUS argument -const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageVector &iconVector) -{ - argument.beginArray(qMetaTypeId()); - for (int i = 0; i < iconVector.size(); ++i) { - argument << iconVector[i]; - } - argument.endArray(); - return argument; -} - -// Retrieve the ImageVector data from the D-BUS argument -const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusImageVector &iconVector) -{ - argument.beginArray(); - iconVector.clear(); - - while (!argument.atEnd()) { - KDbusImageStruct element; - argument >> element; - iconVector.append(element); - } - - argument.endArray(); - - return argument; -} - -// Marshall the ToolTipStruct data into a D-BUS argument -const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusToolTipStruct &toolTip) -{ - argument.beginStructure(); - argument << toolTip.icon; - argument << toolTip.image; - argument << toolTip.title; - argument << toolTip.subTitle; - argument.endStructure(); - return argument; -} - -// Retrieve the ToolTipStruct data from the D-BUS argument -const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusToolTipStruct &toolTip) -{ - QString icon; - KDbusImageVector image; - QString title; - QString subTitle; - - argument.beginStructure(); - argument >> icon; - argument >> image; - argument >> title; - argument >> subTitle; - argument.endStructure(); - - toolTip.icon = icon; - toolTip.image = image; - toolTip.title = title; - toolTip.subTitle = subTitle; - - return argument; -} diff --git a/xembed-sni-proxy/snidbus.h b/xembed-sni-proxy/snidbus.h deleted file mode 100644 index 87ba1ed..0000000 --- a/xembed-sni-proxy/snidbus.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - SNI Dbus serialisers - Copyright 2015 David Edmundson - - SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL -*/ - -#pragma once - -#include -#include -#include -#include -#include - -// Custom message type for DBus -struct KDbusImageStruct { - KDbusImageStruct(); - KDbusImageStruct(const QImage &image); - int width; - int height; - QByteArray data; -}; - -typedef QVector KDbusImageVector; - -struct KDbusToolTipStruct { - QString icon; - KDbusImageVector image; - QString title; - QString subTitle; -}; - -const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageStruct &icon); -const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusImageStruct &icon); - -Q_DECLARE_METATYPE(KDbusImageStruct) - -const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageVector &iconVector); -const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusImageVector &iconVector); - -Q_DECLARE_METATYPE(KDbusImageVector) - -const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusToolTipStruct &toolTip); -const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusToolTipStruct &toolTip); - -Q_DECLARE_METATYPE(KDbusToolTipStruct) diff --git a/xembed-sni-proxy/sniproxy.cpp b/xembed-sni-proxy/sniproxy.cpp deleted file mode 100644 index 107e6ca..0000000 --- a/xembed-sni-proxy/sniproxy.cpp +++ /dev/null @@ -1,597 +0,0 @@ -/* - Holds one embedded window, registers as DBus entry - SPDX-FileCopyrightText: 2015 David Edmundson - SPDX-FileCopyrightText: 2019 Konrad Materka - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#include "sniproxy.h" - -#include -#include -#include - -#include "debug.h" -#include "x11utils.h" -#include "xcbutils.h" - -#include -#include -#include - -#include - -#include -#include -#include - -#include "statusnotifieritemadaptor.h" -#include "statusnotifierwatcher_interface.h" - -#include "xtestsender.h" - -//#define VISUAL_DEBUG - -#define SNI_WATCHER_SERVICE_NAME "org.kde.StatusNotifierWatcher" -#define SNI_WATCHER_PATH "/StatusNotifierWatcher" - -static uint16_t s_embedSize = 32; // max size of window to embed. We no longer resize the embedded window as Chromium acts stupidly. -static unsigned int XEMBED_VERSION = 0; - -int SNIProxy::s_serviceCount = 0; - -void xembed_message_send(xcb_window_t towin, long message, long d1, long d2, long d3) -{ - xcb_client_message_event_t ev; - - ev.response_type = XCB_CLIENT_MESSAGE; - ev.window = towin; - ev.format = 32; - ev.data.data32[0] = XCB_CURRENT_TIME; - ev.data.data32[1] = message; - ev.data.data32[2] = d1; - ev.data.data32[3] = d2; - ev.data.data32[4] = d3; - ev.type = Xcb::atoms->xembedAtom; - xcb_send_event(qGuiApp->nativeInterface()->connection(), false, towin, XCB_EVENT_MASK_NO_EVENT, (char *)&ev); -} - -SNIProxy::SNIProxy(xcb_window_t wid, QObject *parent) - : QObject(parent) - , - // Work round a bug in our SNIWatcher with multiple SNIs per connection. - // 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_windowId(wid) - , sendingClickEvent(false) - , m_injectMode(Direct) -{ - // create new SNI - new StatusNotifierItemAdaptor(this); - m_dbus.registerObject(QStringLiteral("/StatusNotifierItem"), this); - - auto statusNotifierWatcher = - new org::kde::StatusNotifierWatcher(QStringLiteral(SNI_WATCHER_SERVICE_NAME), QStringLiteral(SNI_WATCHER_PATH), QDBusConnection::sessionBus(), this); - auto reply = statusNotifierWatcher->RegisterStatusNotifierItem(m_dbus.baseService()); - reply.waitForFinished(); - if (reply.isError()) { - qCWarning(SNIPROXY) << "could not register SNI:" << reply.error().message(); - } - - auto c = qGuiApp->nativeInterface()->connection(); - - // create a container window - auto screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data; - m_containerWid = xcb_generate_id(c); - 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 - values[1] = true; // bypass wM - 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_COPY_FROM_PARENT, /* depth */ - m_containerWid, /* window Id */ - screen->root, /* parent window */ - 0, - 0, /* x, y */ - s_embedSize, - s_embedSize, /* width, height */ - 0, /* border_width */ - XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */ - screen->root_visual, /* visual */ - mask, - values); /* masks */ - - /* - We need the window to exist and be mapped otherwise the child won't render it's contents - - We also need it to exist in the right place to get the clicks working as GTK will check sendEvent locations to see if our window is in the right place. - So even though our contents are drawn via compositing we still put this window in the right place - - We can't composite it away anything parented owned by the root window (apparently) - Stack Under works in the non composited case, but it doesn't seem to work in kwin's composited case (probably need set relevant NETWM hint) - - As a last resort set opacity to 0 just to make sure this container never appears - */ - -#ifndef VISUAL_DEBUG - stackContainerWindow(XCB_STACK_MODE_BELOW); - - NETWinInfo wm(c, m_containerWid, screen->root, NET::Properties(), NET::Properties2()); - wm.setOpacity(0); -#endif - - xcb_flush(c); - - xcb_map_window(c, m_containerWid); - - xcb_reparent_window(c, wid, m_containerWid, 0, 0); - - /* - * Render the embedded window offscreen - */ - xcb_composite_redirect_window(c, wid, 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, wid); - - // tell client we're embedding it - xembed_message_send(wid, XEMBED_EMBEDDED_NOTIFY, 0, m_containerWid, XEMBED_VERSION); - - // move window we're embedding - const uint32_t windowMoveConfigVals[2] = {0, 0}; - - xcb_configure_window(c, wid, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, windowMoveConfigVals); - - QSize clientWindowSize = calculateClientWindowSize(); - - // show the embedded window otherwise nothing happens - xcb_map_window(c, wid); - - xcb_clear_area(c, 0, wid, 0, 0, clientWindowSize.width(), clientWindowSize.height()); - - xcb_flush(c); - - // guess which input injection method to use - // we can either send an X event to the client or XTest - // some don't support direct X events (GTK3/4), and some don't support XTest because reasons - // note also some clients might not have the XTest extension. We may as well assume it does and just fail to send later. - - // 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, wid); - QScopedPointer windowAttributes(xcb_get_window_attributes_reply(c, waCookie, nullptr)); - if (windowAttributes && !(windowAttributes->all_event_masks & XCB_EVENT_MASK_BUTTON_PRESS)) { - m_injectMode = XTest; - } - - // there's no damage event for the first paint, and sometimes it's not drawn immediately - // not ideal, but it works better than nothing - // test with xchat before changing - QTimer::singleShot(500, this, &SNIProxy::update); -} - -SNIProxy::~SNIProxy() -{ - auto c = qGuiApp->nativeInterface()->connection(); - - xcb_destroy_window(c, m_containerWid); - QDBusConnection::disconnectFromBus(m_dbus.name()); -} - -void SNIProxy::update() -{ - const QImage image = getImageNonComposite(); - if (image.isNull()) { - qCDebug(SNIPROXY) << "No xembed icon for" << m_windowId << Title(); - return; - } - - int w = image.width(); - int h = image.height(); - - m_pixmap = QPixmap::fromImage(image); - if (w > s_embedSize || h > s_embedSize) { - qCDebug(SNIPROXY) << "Scaling pixmap of window" << m_windowId << Title() << "from w*h" << w << h; - m_pixmap = m_pixmap.scaled(s_embedSize, s_embedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); - } - emit NewIcon(); - emit NewToolTip(); -} - -void SNIProxy::resizeWindow(const uint16_t width, const uint16_t height) const -{ - auto connection = qGuiApp->nativeInterface()->connection(); - - uint16_t widthNormalized = std::min(width, s_embedSize); - uint16_t heighNormalized = std::min(height, s_embedSize); - - const uint32_t windowSizeConfigVals[2] = {widthNormalized, heighNormalized}; - xcb_configure_window(connection, m_windowId, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, windowSizeConfigVals); - - xcb_flush(connection); -} - -void SNIProxy::hideContainerWindow(xcb_window_t windowId) const -{ - if (m_containerWid == windowId && !sendingClickEvent) { - qDebug() << "Container window visible, stack below"; - stackContainerWindow(XCB_STACK_MODE_BELOW); - } -} - -QSize SNIProxy::calculateClientWindowSize() const -{ - auto c = qGuiApp->nativeInterface()->connection(); - - auto cookie = xcb_get_geometry(c, m_windowId); - QScopedPointer clientGeom(xcb_get_geometry_reply(c, cookie, nullptr)); - - QSize clientWindowSize; - if (clientGeom) { - clientWindowSize = QSize(clientGeom->width, clientGeom->height); - } - // if the window is a clearly stupid size resize to be something sensible - // this is needed as chromium and such when resized just fill the icon with transparent space and only draw in the middle - // however KeePass2 does need this as by default the window size is 273px wide and is not transparent - // use an arbitrary heuristic to make sure icons are always sensible - if (clientWindowSize.isEmpty() || clientWindowSize.width() > s_embedSize || clientWindowSize.height() > s_embedSize) { - qCDebug(SNIPROXY) << "Resizing window" << m_windowId << Title() << "from w*h" << clientWindowSize; - - resizeWindow(s_embedSize, s_embedSize); - - clientWindowSize = QSize(s_embedSize, s_embedSize); - } - - return clientWindowSize; -} - -void sni_cleanup_xcb_image(void *data) -{ - xcb_image_destroy(static_cast(data)); -} - -bool SNIProxy::isTransparentImage(const QImage &image) const -{ - int w = image.width(); - int h = image.height(); - - // check for the center and sub-center pixels first and avoid full image scan - if (!(qAlpha(image.pixel(w >> 1, h >> 1)) + qAlpha(image.pixel(w >> 2, h >> 2)) == 0)) - return false; - - // skip scan altogether if sub-center pixel found to be opaque - // and break out from the outer loop too on full scan - for (int x = 0; x < w; ++x) { - for (int y = 0; y < h; ++y) { - if (qAlpha(image.pixel(x, y))) { - // Found an opaque pixel. - return false; - } - } - } - - return true; -} - -QImage SNIProxy::getImageNonComposite() const -{ - auto c = qGuiApp->nativeInterface()->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); - - // Don't hook up cleanup yet, we may use a different QImage after all - QImage naiveConversion; - if (image) { - naiveConversion = QImage(image->data, image->width, image->height, QImage::Format_ARGB32); - } else { - qCDebug(SNIPROXY) << "Skip NULL image returned from xcb_image_get() for" << m_windowId << Title(); - return QImage(); - } - - if (isTransparentImage(naiveConversion)) { - QImage elaborateConversion = QImage(convertFromNative(image)); - - // Update icon only if it is at least partially opaque. - // This is just a workaround for X11 bug: xembed icon may suddenly - // become transparent for a one or few frames. Reproducible at least - // with WINE applications. - if (isTransparentImage(elaborateConversion)) { - qCDebug(SNIPROXY) << "Skip transparent xembed icon for" << m_windowId << Title(); - return QImage(); - } else - return elaborateConversion; - } else { - // Now we are sure we can eventually delete the xcb_image_t with this version - return QImage(image->data, image->width, image->height, image->stride, QImage::Format_ARGB32, sni_cleanup_xcb_image, image); - } -} - -QImage SNIProxy::convertFromNative(xcb_image_t *xcbImage) const -{ - QImage::Format format = QImage::Format_Invalid; - - switch (xcbImage->depth) { - case 1: - format = QImage::Format_MonoLSB; - break; - case 16: - format = QImage::Format_RGB16; - break; - case 24: - format = QImage::Format_RGB32; - break; - case 30: { - // Qt doesn't have a matching image format. We need to convert manually - quint32 *pixels = reinterpret_cast(xcbImage->data); - for (uint i = 0; i < (xcbImage->size / 4); i++) { - int r = (pixels[i] >> 22) & 0xff; - int g = (pixels[i] >> 12) & 0xff; - int b = (pixels[i] >> 2) & 0xff; - - pixels[i] = qRgba(r, g, b, 0xff); - } - // fall through, Qt format is still Format_ARGB32_Premultiplied - Q_FALLTHROUGH(); - } - case 32: - format = QImage::Format_ARGB32_Premultiplied; - break; - default: - return QImage(); // we don't know - } - - QImage image(xcbImage->data, xcbImage->width, xcbImage->height, xcbImage->stride, format, sni_cleanup_xcb_image, xcbImage); - - if (image.isNull()) { - return QImage(); - } - - if (format == QImage::Format_RGB32 && xcbImage->bpp == 32) { - QImage m = image.createHeuristicMask(); - QBitmap mask(QPixmap::fromImage(m)); - QPixmap p = QPixmap::fromImage(image); - p.setMask(mask); - image = p.toImage(); - } - - // work around an abort in QImage::color - if (image.format() == QImage::Format_MonoLSB) { - image.setColorCount(2); - image.setColor(0, QColor(Qt::white).rgb()); - image.setColor(1, QColor(Qt::black).rgb()); - } - - return image; -} - -/* - Wine is using XWindow Shape Extension for transparent tray icons. - We need to find first clickable point starting from top-left. -*/ -QPoint SNIProxy::calculateClickPoint() const -{ - QPoint clickPoint = QPoint(0, 0); - - auto c = qGuiApp->nativeInterface()->connection(); - - // request extent to check if shape has been set - xcb_shape_query_extents_cookie_t extentsCookie = xcb_shape_query_extents(c, 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); - - QScopedPointer extentsReply(xcb_shape_query_extents_reply(c, extentsCookie, nullptr)); - QScopedPointer rectanglesReply(xcb_shape_get_rectangles_reply(c, rectaglesCookie, nullptr)); - - if (!extentsReply || !rectanglesReply || !extentsReply->bounding_shaped) { - return clickPoint; - } - - xcb_rectangle_t *rectangles = xcb_shape_get_rectangles_rectangles(rectanglesReply.get()); - if (!rectangles) { - return clickPoint; - } - - const QImage image = getImageNonComposite(); - - double minLength = sqrt(pow(image.height(), 2) + pow(image.width(), 2)); - const int nRectangles = xcb_shape_get_rectangles_rectangles_length(rectanglesReply.get()); - for (int i = 0; i < nRectangles; ++i) { - double length = sqrt(pow(rectangles[i].x, 2) + pow(rectangles[i].y, 2)); - if (length < minLength) { - minLength = length; - clickPoint = QPoint(rectangles[i].x, rectangles[i].y); - } - } - - qCDebug(SNIPROXY) << "Click point:" << clickPoint; - return clickPoint; -} - -void SNIProxy::stackContainerWindow(const uint32_t stackMode) const -{ - auto c = qGuiApp->nativeInterface()->connection(); - const uint32_t stackData[] = {stackMode}; - xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackData); -} - -//____________properties__________ - -QString SNIProxy::Category() const -{ - return QStringLiteral("ApplicationStatus"); -} - -QString SNIProxy::Id() const -{ - const auto title = Title(); - // we always need /some/ ID so if no window title exists, just use the winId. - if (title.isEmpty()) { - return QString::number(m_windowId); - } - return title; -} - -KDbusImageVector SNIProxy::IconPixmap() const -{ - KDbusImageStruct dbusImage(m_pixmap.toImage()); - return KDbusImageVector() << dbusImage; -} - -bool SNIProxy::ItemIsMenu() const -{ - return false; -} - -QString SNIProxy::Status() const -{ - return QStringLiteral("Active"); -} - -QString SNIProxy::Title() const -{ - KWindowInfo window(m_windowId, NET::WMName); - return window.name(); -} - -int SNIProxy::WindowId() const -{ - return m_windowId; -} - -//____________actions_____________ - -void SNIProxy::Activate(int x, int y) -{ - sendClick(XCB_BUTTON_INDEX_1, x, y); -} - -void SNIProxy::SecondaryActivate(int x, int y) -{ - sendClick(XCB_BUTTON_INDEX_2, x, y); -} - -void SNIProxy::ContextMenu(int x, int y) -{ - sendClick(XCB_BUTTON_INDEX_3, x, y); -} - -void SNIProxy::Scroll(int delta, const QString &orientation) -{ - if (orientation == QLatin1String("vertical")) { - sendClick(delta > 0 ? XCB_BUTTON_INDEX_4 : XCB_BUTTON_INDEX_5, 0, 0); - } else { - sendClick(delta > 0 ? 6 : 7, 0, 0); - } -} - -void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) -{ - // it's best not to look at this code - // GTK doesn't like send_events and double checks the mouse position matches where the window is and is top level - // in order to solve this we move the embed container over to where the mouse is then replay the event using send_event - // if patching, test with xchat + xchat context menus - - // note x,y are not actually where the mouse is, but the plasmoid - // ideally we should make this match the plasmoid hit area - - qCDebug(SNIPROXY) << "Received click" << mouseButton << "with passed x*y" << x << y; - sendingClickEvent = true; - - auto c = qGuiApp->nativeInterface()->connection(); - - auto cookieSize = xcb_get_geometry(c, m_windowId); - QScopedPointer clientGeom(xcb_get_geometry_reply(c, cookieSize, nullptr)); - - if (!clientGeom) { - return; - } - - auto cookie = xcb_query_pointer(c, m_windowId); - QScopedPointer pointer(xcb_query_pointer_reply(c, cookie, nullptr)); - /*qCDebug(SNIPROXY) << "samescreen" << pointer->same_screen << endl - << "root x*y" << pointer->root_x << pointer->root_y << endl - << "win x*y" << pointer->win_x << pointer->win_y;*/ - - // move our window so the mouse is within its geometry - uint32_t configVals[2] = {0, 0}; - const QPoint clickPoint = calculateClickPoint(); - if (mouseButton >= XCB_BUTTON_INDEX_4) { - // scroll event, take pointer position - configVals[0] = pointer->root_x; - configVals[1] = pointer->root_y; - } else { - if (pointer->root_x > x + clientGeom->width) - configVals[0] = pointer->root_x - clientGeom->width + 1; - else - configVals[0] = static_cast(x - clickPoint.x()); - if (pointer->root_y > y + clientGeom->height) - configVals[1] = pointer->root_y - clientGeom->height + 1; - else - configVals[1] = static_cast(y - clickPoint.y()); - } - xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, configVals); - - // pull window up - stackContainerWindow(XCB_STACK_MODE_ABOVE); - - // 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; - event->same_screen = 1; - event->root = Cutefish::X11::rootWindow(); - event->root_x = x; - event->root_y = y; - event->event_x = static_cast(clickPoint.x()); - event->event_y = static_cast(clickPoint.y()); - event->child = 0; - event->state = 0; - event->detail = mouseButton; - - xcb_send_event(c, false, m_windowId, XCB_EVENT_MASK_BUTTON_PRESS, (char *)event); - delete event; - } else { - sendXTestPressed(qGuiApp->nativeInterface()->display(), mouseButton); - } - - // mouse up - if (m_injectMode == Direct) { - xcb_button_release_event_t *event = new xcb_button_release_event_t; - memset(event, 0x00, sizeof(xcb_button_release_event_t)); - event->response_type = XCB_BUTTON_RELEASE; - event->event = m_windowId; - event->time = XCB_CURRENT_TIME; - event->same_screen = 1; - event->root = Cutefish::X11::rootWindow(); - event->root_x = x; - event->root_y = y; - event->event_x = static_cast(clickPoint.x()); - event->event_y = static_cast(clickPoint.y()); - event->child = 0; - event->state = 0; - event->detail = mouseButton; - - xcb_send_event(c, false, m_windowId, XCB_EVENT_MASK_BUTTON_RELEASE, (char *)event); - delete event; - } else { - sendXTestReleased(qGuiApp->nativeInterface()->display(), mouseButton); - } - -#ifndef VISUAL_DEBUG - stackContainerWindow(XCB_STACK_MODE_BELOW); -#endif - - sendingClickEvent = false; -} diff --git a/xembed-sni-proxy/sniproxy.h b/xembed-sni-proxy/sniproxy.h deleted file mode 100644 index ddb87c2..0000000 --- a/xembed-sni-proxy/sniproxy.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - Holds one embedded window, registers as DBus entry - SPDX-FileCopyrightText: 2015 David Edmundson - SPDX-FileCopyrightText: 2019 Konrad Materka - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef Status -#undef Status -#endif -#ifdef None -#undef None -#endif - -#include "snidbus.h" - -class SNIProxy : public QObject -{ - Q_OBJECT - Q_PROPERTY(QString Category READ Category) - Q_PROPERTY(QString Id READ Id) - Q_PROPERTY(QString Title READ Title) - Q_PROPERTY(QString Status READ Status) - Q_PROPERTY(int WindowId READ WindowId) - Q_PROPERTY(bool ItemIsMenu READ ItemIsMenu) - Q_PROPERTY(KDbusImageVector IconPixmap READ IconPixmap) - -public: - explicit SNIProxy(xcb_window_t wid, QObject *parent = nullptr); - ~SNIProxy() override; - - void update(); - void resizeWindow(const uint16_t width, const uint16_t height) const; - void hideContainerWindow(xcb_window_t windowId) const; - - /** - * @return the category of the application associated to this item - * @see Category - */ - QString Category() const; - - /** - * @return the id of this item - */ - QString Id() const; - - /** - * @return the title of this item - */ - QString Title() const; - - /** - * @return The status of this item - * @see Status - */ - QString Status() const; - - /** - * @return The id of the main window of the application that controls the item - */ - int WindowId() const; - - /** - * @return The item only support the context menu, the visualization should prefer sending ContextMenu() instead of Activate() - */ - bool ItemIsMenu() const; - - /** - * @return a serialization of the icon data - */ - KDbusImageVector IconPixmap() const; - -public Q_SLOTS: - // interaction - /** - * Shows the context menu associated to this item - * at the desired screen position - */ - void ContextMenu(int x, int y); - - /** - * Shows the main widget and try to position it on top - * of the other windows, if the widget is already visible, hide it. - */ - void Activate(int x, int y); - - /** - * The user activated the item in an alternate way (for instance with middle mouse button, this depends from the systray implementation) - */ - void SecondaryActivate(int x, int y); - - /** - * Inform this item that the mouse wheel was used on its representation - */ - void Scroll(int delta, const QString &orientation); - -Q_SIGNALS: - /** - * Inform the systemtray that the own main icon has been changed, - * so should be reloaded - */ - void NewIcon(); - - /** - * Inform the systemtray that there is a new icon to be used as overlay - */ - void NewOverlayIcon(); - - /** - * Inform the systemtray that the requesting attention icon - * has been changed, so should be reloaded - */ - void NewAttentionIcon(); - - /** - * Inform the systemtray that something in the tooltip has been changed - */ - void NewToolTip(); - - /** - * Signal the new status when it has been changed - * @see Status - */ - void NewStatus(const QString &status); - -private: - enum InjectMode { - Direct, - XTest, - }; - - QSize calculateClientWindowSize() const; - void sendClick(uint8_t mouseButton, int x, int y); - QImage getImageNonComposite() const; - bool isTransparentImage(const QImage &image) const; - QImage convertFromNative(xcb_image_t *xcbImage) const; - QPoint calculateClickPoint() const; - void stackContainerWindow(const uint32_t stackMode) const; - - QDBusConnection m_dbus; - xcb_window_t m_windowId; - xcb_window_t m_containerWid; - static int s_serviceCount; - QPixmap m_pixmap; - bool sendingClickEvent; - InjectMode m_injectMode; -}; diff --git a/xembed-sni-proxy/xcbutils.h b/xembed-sni-proxy/xcbutils.h deleted file mode 100644 index 6b0ba57..0000000 --- a/xembed-sni-proxy/xcbutils.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - SPDX-FileCopyrightText: 2012, 2013 Martin Graesslin - SPDX-FileCopyrightText: 2015 David Edmudson - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "x11utils.h" - -/** XEMBED messages */ -#define XEMBED_EMBEDDED_NOTIFY 0 -#define XEMBED_WINDOW_ACTIVATE 1 -#define XEMBED_WINDOW_DEACTIVATE 2 -#define XEMBED_REQUEST_FOCUS 3 -#define XEMBED_FOCUS_IN 4 -#define XEMBED_FOCUS_OUT 5 -#define XEMBED_FOCUS_NEXT 6 -#define XEMBED_FOCUS_PREV 7 - -namespace Xcb -{ -typedef xcb_window_t WindowId; - -template -using ScopedCPointer = QScopedPointer; - -class Atom -{ -public: - explicit Atom(const QByteArray &name, bool onlyIfExists = false, xcb_connection_t *c = qGuiApp->nativeInterface()->connection()) - : m_connection(c) - , m_retrieved(false) - , m_cookie(xcb_intern_atom_unchecked(m_connection, onlyIfExists, name.length(), name.constData())) - , m_atom(XCB_ATOM_NONE) - , m_name(name) - { - } - Atom() = delete; - Atom(const Atom &) = delete; - - ~Atom() - { - if (!m_retrieved && m_cookie.sequence) { - xcb_discard_reply(m_connection, m_cookie.sequence); - } - } - - operator xcb_atom_t() const - { - (const_cast(this))->getReply(); - return m_atom; - } - bool isValid() - { - getReply(); - return m_atom != XCB_ATOM_NONE; - } - bool isValid() const - { - (const_cast(this))->getReply(); - return m_atom != XCB_ATOM_NONE; - } - - inline const QByteArray &name() const - { - return m_name; - } - -private: - void getReply() - { - if (m_retrieved || !m_cookie.sequence) { - return; - } - ScopedCPointer reply(xcb_intern_atom_reply(m_connection, m_cookie, nullptr)); - if (!reply.isNull()) { - m_atom = reply->atom; - } - m_retrieved = true; - } - xcb_connection_t *m_connection; - bool m_retrieved; - xcb_intern_atom_cookie_t m_cookie; - xcb_atom_t m_atom; - QByteArray m_name; -}; - -class Atoms -{ -public: - Atoms() - : xembedAtom("_XEMBED") - , selectionAtom(xcb_atom_name_by_screen("_NET_SYSTEM_TRAY", Cutefish::X11::screenNumber())) - , opcodeAtom("_NET_SYSTEM_TRAY_OPCODE") - , messageData("_NET_SYSTEM_TRAY_MESSAGE_DATA") - , visualAtom("_NET_SYSTEM_TRAY_VISUAL") - { - } - - Atom xembedAtom; - Atom selectionAtom; - Atom opcodeAtom; - Atom messageData; - Atom visualAtom; -}; - -extern Atoms *atoms; - -} // namespace Xcb diff --git a/xembed-sni-proxy/xtestsender.cpp b/xembed-sni-proxy/xtestsender.cpp deleted file mode 100644 index 69833d4..0000000 --- a/xembed-sni-proxy/xtestsender.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* Wrap XLIB code in a new file as it defines keywords that conflict with Qt - - SPDX-FileCopyrightText: 2017 David Edmundson - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ - -#include "xtestsender.h" -#include - -void sendXTestPressed(Display *display, int button) -{ - XTestFakeButtonEvent(display, button, true, 0); -} - -void sendXTestReleased(Display *display, int button) -{ - XTestFakeButtonEvent(display, button, false, 0); -} diff --git a/xembed-sni-proxy/xtestsender.h b/xembed-sni-proxy/xtestsender.h deleted file mode 100644 index 50176bd..0000000 --- a/xembed-sni-proxy/xtestsender.h +++ /dev/null @@ -1,12 +0,0 @@ -/* Wrap XLIB code in a new file as it defines keywords that conflict with Qt - - SPDX-FileCopyrightText: 2017 David Edmundson - - SPDX-License-Identifier: LGPL-2.1-or-later -*/ -#pragma once - -typedef struct _XDisplay Display; - -void sendXTestPressed(Display *display, int button); -void sendXTestReleased(Display *display, int button);