Hello community, here is the log from the commit of package kguiaddons for openSUSE:Factory checked in at 2020-12-15 12:27:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kguiaddons (Old) and /work/SRC/openSUSE:Factory/.kguiaddons.new.2328 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kguiaddons" Tue Dec 15 12:27:48 2020 rev:85 rq:855363 version:5.77.0 Changes: -------- --- /work/SRC/openSUSE:Factory/kguiaddons/kguiaddons.changes 2020-11-23 10:32:18.381480716 +0100 +++ /work/SRC/openSUSE:Factory/.kguiaddons.new.2328/kguiaddons.changes 2020-12-15 12:27:58.923884166 +0100 @@ -1,0 +2,20 @@ +Sat Dec 12 13:35:03 UTC 2020 - Wolfgang Bauer <[email protected]> + +- Explicitly BuildRequire pkgconfig(wayland-client) that's needed + now and don't rely on other packages pulling it in + +------------------------------------------------------------------- +Sat Dec 5 18:56:34 UTC 2020 - Christophe Giboudeaux <[email protected]> + +- Update to 5.77.0 + * New feature release + * For more details please see: + * https://kde.org/announcements/kde-frameworks-5.77.0 +- Changes since 5.76.0: + * Remove redundant setLayout() call (parent is passed to Q*Layout ctor) + * Make shortcut inhibition work from the get-go (kde#407395) + * Fix potential crash in wayland inhibitor teardown (kde#429267) + * CMake: Find Qt5::GuiPrivate when Wayland support is enabled + * Add KeySequenceRecorder as base for KKeySequenceWidget and KeySequenceItem + +------------------------------------------------------------------- Old: ---- kguiaddons-5.76.0.tar.xz kguiaddons-5.76.0.tar.xz.sig New: ---- kguiaddons-5.77.0.tar.xz kguiaddons-5.77.0.tar.xz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kguiaddons.spec ++++++ --- /var/tmp/diff_new_pack.1859sN/_old 2020-12-15 12:27:59.559884678 +0100 +++ /var/tmp/diff_new_pack.1859sN/_new 2020-12-15 12:27:59.563884681 +0100 @@ -17,7 +17,7 @@ %define lname libKF5GuiAddons5 -%define _tar_path 5.76 +%define _tar_path 5.77 # Full KF5 version (e.g. 5.33.0) %{!?_kf5_version: %global _kf5_version %{version}} # Last major and minor KF5 version (e.g. 5.33) @@ -25,7 +25,7 @@ # Only needed for the package signature condition %bcond_without lang Name: kguiaddons -Version: 5.76.0 +Version: 5.77.0 Release: 0 Summary: Utilities for graphical user interfaces License: LGPL-2.1-or-later @@ -40,12 +40,14 @@ BuildRequires: extra-cmake-modules >= %{_kf5_bugfix_version} BuildRequires: fdupes BuildRequires: kf5-filesystem +BuildRequires: libQt5Gui-private-headers-devel BuildRequires: pkgconfig -BuildRequires: cmake(Qt5Gui) >= 5.12.0 -# Tests -BuildRequires: cmake(Qt5Test) >= 5.12.0 -BuildRequires: cmake(Qt5Widgets) >= 5.12.0 -BuildRequires: cmake(Qt5X11Extras) >= 5.12.0 +BuildRequires: cmake(Qt5Gui) >= 5.13.0 +BuildRequires: cmake(Qt5Test) >= 5.13.0 +BuildRequires: cmake(Qt5WaylandClient) >= 5.13.0 +BuildRequires: cmake(Qt5Widgets) >= 5.13.0 +BuildRequires: cmake(Qt5X11Extras) >= 5.13.0 +BuildRequires: pkgconfig(wayland-client) BuildRequires: pkgconfig(x11) BuildRequires: pkgconfig(xcb) @@ -67,7 +69,7 @@ Group: Development/Libraries/KDE Requires: %{lname} = %{version} Requires: extra-cmake-modules -Requires: cmake(Qt5Gui) >= 5.12.0 +Requires: cmake(Qt5Gui) >= 5.13.0 %description devel The KDE GUI addons provide utilities for graphical user interfaces in the areas ++++++ kguiaddons-5.76.0.tar.xz -> kguiaddons-5.77.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-5.76.0/CMakeLists.txt new/kguiaddons-5.77.0/CMakeLists.txt --- old/kguiaddons-5.76.0/CMakeLists.txt 2020-11-07 12:37:58.000000000 +0100 +++ new/kguiaddons-5.77.0/CMakeLists.txt 2020-12-05 11:07:55.000000000 +0100 @@ -1,27 +1,48 @@ cmake_minimum_required(VERSION 3.5) -set(KF5_VERSION "5.76.0") # handled by release scripts +set(KF5_VERSION "5.77.0") # handled by release scripts project(KGuiAddons VERSION ${KF5_VERSION}) include(FeatureSummary) -find_package(ECM 5.76.0 NO_MODULE) +find_package(ECM 5.77.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) + +option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) +add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") + +if (UNIX AND NOT ANDROID) + option(WITH_WAYLAND "Build with support for KeySequenceEditor inhibiting shortcuts on Wayland" ON) + add_feature_info(WAYLAND ${WITH_WAYLAND} "KeySequenceEditor inhibiting shortcuts on Wayland") +else() + set(WITH_WAYLAND OFF) +endif() + set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) -set(REQUIRED_QT_VERSION 5.12.0) -find_package(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE) + +set(REQUIRED_QT_VERSION 5.13.0) +if (WITH_WAYLAND) + set(_qtgui_find_components COMPONENTS Private) +endif() +# QtGui must be found becore Qt5WaylandClient +find_package(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE ${_qtgui_find_components}) if (NOT APPLE AND NOT WIN32) find_package(X11 MODULE) find_package(XCB MODULE COMPONENTS XCB) endif() +if (WITH_WAYLAND) + find_package(Qt5WaylandClient ${REQUIRED_QT_VERSION} NO_MODULE) + find_package(QtWaylandScanner REQUIRED) + find_package(Wayland 1.9 REQUIRED Client) +endif() include(GenerateExportHeader) include(ECMSetupVersion) @@ -34,8 +55,7 @@ PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5GuiAddonsConfigVersion.cmake" SOVERSION 5) -option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) -add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") + add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050d00) add_definitions(-DQT_NO_FOREACH) add_subdirectory(src) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-5.76.0/autotests/CMakeLists.txt new/kguiaddons-5.77.0/autotests/CMakeLists.txt --- old/kguiaddons-5.76.0/autotests/CMakeLists.txt 2020-11-07 12:37:58.000000000 +0100 +++ new/kguiaddons-5.77.0/autotests/CMakeLists.txt 2020-12-05 11:07:55.000000000 +0100 @@ -9,5 +9,6 @@ kcolorutilstest.cpp kiconutilstest.cpp kcursorsavertest.cpp + keysequencerecordertest.cpp LINK_LIBRARIES KF5::GuiAddons Qt5::Test ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-5.76.0/autotests/keysequencerecordertest.cpp new/kguiaddons-5.77.0/autotests/keysequencerecordertest.cpp --- old/kguiaddons-5.76.0/autotests/keysequencerecordertest.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/kguiaddons-5.77.0/autotests/keysequencerecordertest.cpp 2020-12-05 11:07:55.000000000 +0100 @@ -0,0 +1,168 @@ +/* + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL + SPDX-FileCopyrightText: 2020 David Redondo <[email protected]> +*/ + +#include "keysequencerecordertest.h" + +#include <KeySequenceRecorder> + +#include <QtTest> +#include <QWindow> + +QTEST_MAIN(KeySequenceRecorderTest) + +void KeySequenceRecorderTest::initTestCase() +{ + m_window = new QWindow; +} + +void KeySequenceRecorderTest::cleanupTestCase() +{ + delete m_window; +} + +void KeySequenceRecorderTest::testValidWindow() +{ + KeySequenceRecorder recorder(nullptr); + QSignalSpy recordingSpy(&recorder, &KeySequenceRecorder::recordingChanged); + + recorder.startRecording(); + QCOMPARE(recordingSpy.count(), 0); + QVERIFY(!recorder.isRecording()); + + recorder.setWindow(m_window); + recorder.startRecording(); + QCOMPARE(recordingSpy.count(), 1); + QVERIFY(recorder.isRecording()); +} + +void KeySequenceRecorderTest::testRecording() +{ + KeySequenceRecorder recorder(m_window); + QSignalSpy recordingSpy(&recorder, &KeySequenceRecorder::recordingChanged); + QSignalSpy sequenceSpy(&recorder, &KeySequenceRecorder::currentKeySequenceChanged); + QSignalSpy resultSpy(&recorder, &KeySequenceRecorder::gotKeySequence); + + recorder.startRecording(); + QVERIFY(recorder.isRecording()); + QCOMPARE(recordingSpy.count(), 1); + QCOMPARE(sequenceSpy.count(), 1); + + QTest::keyClick(m_window, Qt::Key_A, Qt::ControlModifier); + QVERIFY(recorder.isRecording()); + QCOMPARE(recordingSpy.count(), 1); + QCOMPARE(sequenceSpy.count(), 4); // two key events + modifier release + QCOMPARE(resultSpy.count(), 0); + QCOMPARE(recorder.currentKeySequence(), QKeySequence(Qt::Key_A + Qt::ControlModifier)); + + QTest::qWait(800); + QCOMPARE(sequenceSpy.count(), 4); + QCOMPARE(recordingSpy.count(), 2); + QVERIFY(!recorder.isRecording()); + QCOMPARE(resultSpy.count(), 1); + QCOMPARE(recorder.currentKeySequence(), QKeySequence(Qt::Key_A + Qt::ControlModifier)); + QCOMPARE(resultSpy.takeFirst().at(0).value<QKeySequence>(), QKeySequence(Qt::Key_A + Qt::ControlModifier)); +} + +void KeySequenceRecorderTest::testModifiers() +{ + KeySequenceRecorder recorder(m_window); + QSignalSpy recordingSpy(&recorder, &KeySequenceRecorder::recordingChanged); + QSignalSpy sequenceSpy(&recorder, &KeySequenceRecorder::currentKeySequenceChanged); + QSignalSpy resultSpy(&recorder, &KeySequenceRecorder::gotKeySequence); + + recorder.startRecording(); + QCOMPARE(sequenceSpy.count(), 1); + QCOMPARE(recordingSpy.count(), 1); + QVERIFY(recorder.isRecording()); + + QTest::keyPress(m_window, Qt::Key_Control); + QCOMPARE(sequenceSpy.count(), 2); + QCOMPARE(recorder.currentKeySequence(), QKeySequence(Qt::ControlModifier)); + + // Releasing a different key because when releasing Key_Meta, QTest sends a KeyRelease event + // with MetaModifier even though modifieres should be empty + QTest::keyRelease(m_window, Qt::Key_A, Qt::NoModifier); + QCOMPARE(sequenceSpy.count(), 3); + QCOMPARE(recorder.currentKeySequence(), QKeySequence()); + QCOMPARE(recordingSpy.count(), 1); + QVERIFY(recorder.isRecording()); + + QTest::qWait(800); + QVERIFY(recorder.isRecording()); + + QTest::keyPress(m_window, Qt::Key_Control); + QCOMPARE(sequenceSpy.count(), 4); + QCOMPARE(recorder.currentKeySequence(), QKeySequence(Qt::ControlModifier)); + + QTest::keyPress(m_window, Qt::Key_Alt, Qt::ControlModifier); + QCOMPARE(sequenceSpy.count(), 6); // QTest sends two key events, one for each modifier + QCOMPARE(recorder.currentKeySequence(), QKeySequence(Qt::AltModifier + Qt::ControlModifier)); + + QCOMPARE(resultSpy.count(), 0); //modifierless not allowed +} + +void KeySequenceRecorderTest::testModifierless() +{ + KeySequenceRecorder recorder(m_window); + QSignalSpy resultSpy(&recorder, &KeySequenceRecorder::gotKeySequence); + QSignalSpy sequenceSpy(&recorder, &KeySequenceRecorder::currentKeySequenceChanged); + + recorder.startRecording(); + QVERIFY(recorder.isRecording()); + QCOMPARE(sequenceSpy.count(), 1); + + recorder.setModifierlessAllowed(false); + QTest::keyPress(m_window, Qt::Key_A); + QTest::qWait(800); + QVERIFY(recorder.isRecording()); + QCOMPARE(sequenceSpy.count(), 1); + QCOMPARE(resultSpy.count(), 0); + QCOMPARE(recorder.currentKeySequence(), QKeySequence()); + + recorder.setModifierlessAllowed(true); + QTest::keyPress(m_window, Qt::Key_A); + QTest::qWait(800); + QVERIFY(!recorder.isRecording()); + QCOMPARE(sequenceSpy.count(), 2); + QCOMPARE(resultSpy.count(), 1); + QCOMPARE(recorder.currentKeySequence(), QKeySequence(Qt::Key_A)); +} + +void KeySequenceRecorderTest::testMultiKeyAllowed() +{ + KeySequenceRecorder recorder(m_window); + QSignalSpy recordingSpy(&recorder, &KeySequenceRecorder::recordingChanged); + QSignalSpy resultSpy(&recorder, &KeySequenceRecorder::gotKeySequence); + + recorder.startRecording(); + + recorder.setMultiKeyShortcutsAllowed(true); + int keys[4] = {0}; + for (int i = 0; i < 4; ++i) { + QVERIFY(recorder.isRecording()); + QCOMPARE(recordingSpy.count(), 1); + QCOMPARE(resultSpy.count(), 0); + keys[i] = Qt::Key_A + Qt::ControlModifier; + QKeySequence result(keys[0], keys[1], keys[2], keys[3]); + QTest::keyPress(m_window, Qt::Key_A, Qt::ControlModifier); + QTest::keyRelease(m_window, Qt::Key_A, Qt::ControlModifier); + QCOMPARE(recorder.currentKeySequence(), QKeySequence(keys[0], keys[1], keys[2], keys[3])); + } + QVERIFY(!recorder.isRecording()); + QCOMPARE(recordingSpy.count(), 2); + QCOMPARE(resultSpy.count(), 1); + QCOMPARE(resultSpy.takeFirst().at(0).value<QKeySequence>(), QKeySequence(keys[0], keys[1], keys[2], keys[3])); + + recorder.setMultiKeyShortcutsAllowed(false); + recorder.startRecording(); + QVERIFY(recorder.isRecording()); + QCOMPARE(recordingSpy.count(), 3); + QTest::keyPress(m_window, Qt::Key_A, Qt::ControlModifier); + QCOMPARE(recorder.currentKeySequence(), QKeySequence(Qt::Key_A + Qt::ControlModifier)); + QVERIFY(!recorder.isRecording()); + QCOMPARE(recordingSpy.count(), 4); + QCOMPARE(resultSpy.count(), 1); + QCOMPARE(resultSpy.takeAt(0).at(0).value<QKeySequence>(), QKeySequence(Qt::Key_A + Qt::ControlModifier)); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-5.76.0/autotests/keysequencerecordertest.h new/kguiaddons-5.77.0/autotests/keysequencerecordertest.h --- old/kguiaddons-5.76.0/autotests/keysequencerecordertest.h 1970-01-01 01:00:00.000000000 +0100 +++ new/kguiaddons-5.77.0/autotests/keysequencerecordertest.h 2020-12-05 11:07:55.000000000 +0100 @@ -0,0 +1,27 @@ +/* + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL + SPDX-FileCopyrightText: 2020 David Redondo <[email protected]> +*/ + +#ifndef KEYSEQUENCERECORDERTEST_H +#define KEYSEQUENCERECORDERTEST_H + +#include <QObject> + +class QWindow; + +class KeySequenceRecorderTest : public QObject { + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void testValidWindow(); + void testRecording(); + void testModifiers(); + void testModifierless(); + void testMultiKeyAllowed(); +private: + QWindow *m_window; +}; + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-5.76.0/src/CMakeLists.txt new/kguiaddons-5.77.0/src/CMakeLists.txt --- old/kguiaddons-5.76.0/src/CMakeLists.txt 2020-11-07 12:37:58.000000000 +0100 +++ new/kguiaddons-5.77.0/src/CMakeLists.txt 2020-12-05 11:07:55.000000000 +0100 @@ -13,8 +13,11 @@ util/kmodifierkeyinfoprovider.cpp util/urlhandler.cpp util/kcursorsaver.cpp + recorder/keyboardgrabber.cpp + recorder/keysequencerecorder.cpp ) + set (kguiaddons_LIB_SRCS ${kguiaddons_LIB_SRCS} util/kmodifierkeyinfoprovider.cpp) ecm_qt_declare_logging_category(kguiaddons_LIB_SRCS @@ -27,6 +30,16 @@ add_library(KF5GuiAddons ${kguiaddons_LIB_SRCS}) +if(WITH_WAYLAND) + ecm_add_qtwayland_client_protocol(wayland_SRCS + PROTOCOL recorder/keyboard-shortcuts-inhibit-unstable-v1.xml + BASENAME keyboard-shortcuts-inhibit-unstable-v1 + ) + target_sources(KF5GuiAddons PRIVATE recorder/waylandinhibition.cpp ${wayland_SRCS}) + target_compile_definitions(KF5GuiAddons PRIVATE WITH_WAYLAND) + target_link_libraries(KF5GuiAddons PRIVATE Qt5::GuiPrivate Qt5::WaylandClient Wayland::Client) +endif() + generate_export_header(KF5GuiAddons BASE_NAME KGuiAddons) add_library(KF5::GuiAddons ALIAS KF5GuiAddons) @@ -35,6 +48,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/fonts ${CMAKE_CURRENT_SOURCE_DIR}/text ${CMAKE_CURRENT_SOURCE_DIR}/util + ${CMAKE_CURRENT_SOURCE_DIR}/recorder ) target_include_directories(KF5GuiAddons PUBLIC "$<BUILD_INTERFACE:${kguiaddons_INCLUDES}>") target_include_directories(KF5GuiAddons INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF5}/KGuiAddons>" ) @@ -96,6 +110,14 @@ REQUIRED_HEADERS KGuiAddons_HEADERS ) +ecm_generate_headers(KGuiAddons_HEADERS + HEADER_NAMES + KeySequenceRecorder + + RELATIVE recorder + REQUIRED_HEADERS KGuiAddons_HEADERS +) + find_package(PythonModuleGeneration) if (PythonModuleGeneration_FOUND) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-5.76.0/src/recorder/keyboard-shortcuts-inhibit-unstable-v1.xml new/kguiaddons-5.77.0/src/recorder/keyboard-shortcuts-inhibit-unstable-v1.xml --- old/kguiaddons-5.76.0/src/recorder/keyboard-shortcuts-inhibit-unstable-v1.xml 1970-01-01 01:00:00.000000000 +0100 +++ new/kguiaddons-5.77.0/src/recorder/keyboard-shortcuts-inhibit-unstable-v1.xml 2020-12-05 11:07:55.000000000 +0100 @@ -0,0 +1,143 @@ +<?xml version="1.0" encoding="UTF-8"?> +<protocol name="keyboard_shortcuts_inhibit_unstable_v1"> + + <copyright> + Copyright © 2017 Red Hat Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + </copyright> + + <description summary="Protocol for inhibiting the compositor keyboard shortcuts"> + This protocol specifies a way for a client to request the compositor + to ignore its own keyboard shortcuts for a given seat, so that all + key events from that seat get forwarded to a surface. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible + changes may be added together with the corresponding interface + version bump. + Backward incompatible changes are done by bumping the version + number in the protocol and interface names and resetting the + interface version. Once the protocol is to be declared stable, + the 'z' prefix and the version number in the protocol and + interface names are removed and the interface version number is + reset. + </description> + + <interface name="zwp_keyboard_shortcuts_inhibit_manager_v1" version="1"> + <description summary="context object for keyboard grab_manager"> + A global interface used for inhibiting the compositor keyboard shortcuts. + </description> + + <request name="destroy" type="destructor"> + <description summary="destroy the keyboard shortcuts inhibitor object"> + Destroy the keyboard shortcuts inhibitor manager. + </description> + </request> + + <request name="inhibit_shortcuts"> + <description summary="create a new keyboard shortcuts inhibitor object"> + Create a new keyboard shortcuts inhibitor object associated with + the given surface for the given seat. + + If shortcuts are already inhibited for the specified seat and surface, + a protocol error "already_inhibited" is raised by the compositor. + </description> + <arg name="id" type="new_id" interface="zwp_keyboard_shortcuts_inhibitor_v1"/> + <arg name="surface" type="object" interface="wl_surface" + summary="the surface that inhibits the keyboard shortcuts behavior"/> + <arg name="seat" type="object" interface="wl_seat" + summary="the wl_seat for which keyboard shortcuts should be disabled"/> + </request> + + <enum name="error"> + <entry name="already_inhibited" + value="0" + summary="the shortcuts are already inhibited for this surface"/> + </enum> + </interface> + + <interface name="zwp_keyboard_shortcuts_inhibitor_v1" version="1"> + <description summary="context object for keyboard shortcuts inhibitor"> + A keyboard shortcuts inhibitor instructs the compositor to ignore + its own keyboard shortcuts when the associated surface has keyboard + focus. As a result, when the surface has keyboard focus on the given + seat, it will receive all key events originating from the specified + seat, even those which would normally be caught by the compositor for + its own shortcuts. + + The Wayland compositor is however under no obligation to disable + all of its shortcuts, and may keep some special key combo for its own + use, including but not limited to one allowing the user to forcibly + restore normal keyboard events routing in the case of an unwilling + client. The compositor may also use the same key combo to reactivate + an existing shortcut inhibitor that was previously deactivated on + user request. + + When the compositor restores its own keyboard shortcuts, an + "inactive" event is emitted to notify the client that the keyboard + shortcuts inhibitor is not effectively active for the surface and + seat any more, and the client should not expect to receive all + keyboard events. + + When the keyboard shortcuts inhibitor is inactive, the client has + no way to forcibly reactivate the keyboard shortcuts inhibitor. + + The user can chose to re-enable a previously deactivated keyboard + shortcuts inhibitor using any mechanism the compositor may offer, + in which case the compositor will send an "active" event to notify + the client. + + If the surface is destroyed, unmapped, or loses the seat's keyboard + focus, the keyboard shortcuts inhibitor becomes irrelevant and the + compositor will restore its own keyboard shortcuts but no "inactive" + event is emitted in this case. + </description> + + <request name="destroy" type="destructor"> + <description summary="destroy the keyboard shortcuts inhibitor object"> + Remove the keyboard shortcuts inhibitor from the associated wl_surface. + </description> + </request> + + <event name="active"> + <description summary="shortcuts are inhibited"> + This event indicates that the shortcut inhibitor is active. + + The compositor sends this event every time compositor shortcuts + are inhibited on behalf of the surface. When active, the client + may receive input events normally reserved by the compositor + (see zwp_keyboard_shortcuts_inhibitor_v1). + + This occurs typically when the initial request "inhibit_shortcuts" + first becomes active or when the user instructs the compositor to + re-enable and existing shortcuts inhibitor using any mechanism + offered by the compositor. + </description> + </event> + + <event name="inactive"> + <description summary="shortcuts are restored"> + This event indicates that the shortcuts inhibitor is inactive, + normal shortcuts processing is restored by the compositor. + </description> + </event> + </interface> +</protocol> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-5.76.0/src/recorder/keyboardgrabber.cpp new/kguiaddons-5.77.0/src/recorder/keyboardgrabber.cpp --- old/kguiaddons-5.76.0/src/recorder/keyboardgrabber.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/kguiaddons-5.77.0/src/recorder/keyboardgrabber.cpp 2020-12-05 11:07:55.000000000 +0100 @@ -0,0 +1,42 @@ +/* + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL + SPDX-FileCopyrightText: 2020 David Redondo <[email protected]> +*/ + +#include "keyboardgrabber_p.h" + +#include <QWindow> + +KeyboardGrabber::KeyboardGrabber(QWindow *window) + : ShortcutInhibition() + , m_grabbedWindow(window) + , m_grabbingKeyboard(false) +{ +} + +KeyboardGrabber::~KeyboardGrabber() +{ + disableInhibition(); +} + +void KeyboardGrabber::enableInhibition() +{ + if (m_grabbingKeyboard || !m_grabbedWindow) { + return; + } + m_grabbingKeyboard = m_grabbedWindow->setKeyboardGrabEnabled(true); +} + +void KeyboardGrabber::disableInhibition() +{ + if (!m_grabbingKeyboard) { + return; + } + m_grabbingKeyboard = !(m_grabbedWindow->setKeyboardGrabEnabled(false)); +} + +bool KeyboardGrabber::shortcutsAreInhibited() const +{ + return m_grabbingKeyboard; +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-5.76.0/src/recorder/keyboardgrabber_p.h new/kguiaddons-5.77.0/src/recorder/keyboardgrabber_p.h --- old/kguiaddons-5.76.0/src/recorder/keyboardgrabber_p.h 1970-01-01 01:00:00.000000000 +0100 +++ new/kguiaddons-5.77.0/src/recorder/keyboardgrabber_p.h 2020-12-05 11:07:55.000000000 +0100 @@ -0,0 +1,24 @@ +/* + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL + SPDX-FileCopyrightText: 2020 David Redondo <[email protected]> +*/ + +#ifndef GRABBINGINHIBITION_H +#define GRABBINGINHIBITION_H + +#include "shortcutinhibition_p.h" + +class KeyboardGrabber : public ShortcutInhibition +{ +public: + explicit KeyboardGrabber(QWindow *window); + ~KeyboardGrabber(); + void enableInhibition() override; + void disableInhibition() override; + bool shortcutsAreInhibited() const override; +private: + QWindow *m_grabbedWindow; + bool m_grabbingKeyboard; +}; + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-5.76.0/src/recorder/keysequencerecorder.cpp new/kguiaddons-5.77.0/src/recorder/keysequencerecorder.cpp --- old/kguiaddons-5.76.0/src/recorder/keysequencerecorder.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/kguiaddons-5.77.0/src/recorder/keysequencerecorder.cpp 2020-12-05 11:07:55.000000000 +0100 @@ -0,0 +1,492 @@ +/* + SPDX-FileCopyrightText: 1998 Mark Donohoe <[email protected]> + SPDX-FileCopyrightText: 2001 Ellis Whitehead <[email protected]> + SPDX-FileCopyrightText: 2007 Andreas Hartmetz <[email protected]> + SPDX-FileCopyrightText: 2020 David Redondo <[email protected]> + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "keysequencerecorder.h" + +#include "keyboardgrabber_p.h" +#include "kguiaddons_debug.h" +#include "shortcutinhibition_p.h" +#include "waylandinhibition_p.h" + +#include <QGuiApplication> +#include <QKeyEvent> +#include <QPointer> +#include <QTimer> +#include <QWindow> + +#include <array> +#include <memory> + +constexpr Qt::KeyboardModifiers modifierMask = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier | Qt::KeypadModifier; + +// Copied here from KKeyServer +static bool isShiftAsModifierAllowed(int keyQt) +{ + // remove any modifiers + keyQt &= ~Qt::KeyboardModifierMask; + + // Shift only works as a modifier with certain keys. It's not possible + // to enter the SHIFT+5 key sequence for me because this is handled as + // '%' by qt on my keyboard. + // The working keys are all hardcoded here :-( + if (keyQt >= Qt::Key_F1 && keyQt <= Qt::Key_F35) { + return true; + } + + if (QChar(keyQt).isLetter()) { + return true; + } + + switch (keyQt) { + case Qt::Key_Return: + case Qt::Key_Space: + case Qt::Key_Backspace: + case Qt::Key_Tab: + case Qt::Key_Backtab: + case Qt::Key_Escape: + case Qt::Key_Print: + case Qt::Key_ScrollLock: + case Qt::Key_Pause: + case Qt::Key_PageUp: + case Qt::Key_PageDown: + case Qt::Key_Insert: + case Qt::Key_Delete: + case Qt::Key_Home: + case Qt::Key_End: + case Qt::Key_Up: + case Qt::Key_Down: + case Qt::Key_Left: + case Qt::Key_Right: + case Qt::Key_Enter: + case Qt::Key_SysReq: + case Qt::Key_CapsLock: + case Qt::Key_NumLock: + case Qt::Key_Help: + case Qt::Key_Back: + case Qt::Key_Forward: + case Qt::Key_Stop: + case Qt::Key_Refresh: + case Qt::Key_Favorites: + case Qt::Key_LaunchMedia: + case Qt::Key_OpenUrl: + case Qt::Key_HomePage: + case Qt::Key_Search: + case Qt::Key_VolumeDown: + case Qt::Key_VolumeMute: + case Qt::Key_VolumeUp: + case Qt::Key_BassBoost: + case Qt::Key_BassUp: + case Qt::Key_BassDown: + case Qt::Key_TrebleUp: + case Qt::Key_TrebleDown: + case Qt::Key_MediaPlay: + case Qt::Key_MediaStop: + case Qt::Key_MediaPrevious: + case Qt::Key_MediaNext: + case Qt::Key_MediaRecord: + case Qt::Key_MediaPause: + case Qt::Key_MediaTogglePlayPause: + case Qt::Key_LaunchMail: + case Qt::Key_Calculator: + case Qt::Key_Memo: + case Qt::Key_ToDoList: + case Qt::Key_Calendar: + case Qt::Key_PowerDown: + case Qt::Key_ContrastAdjust: + case Qt::Key_Standby: + case Qt::Key_MonBrightnessUp: + case Qt::Key_MonBrightnessDown: + case Qt::Key_KeyboardLightOnOff: + case Qt::Key_KeyboardBrightnessUp: + case Qt::Key_KeyboardBrightnessDown: + case Qt::Key_PowerOff: + case Qt::Key_WakeUp: + case Qt::Key_Eject: + case Qt::Key_ScreenSaver: + case Qt::Key_WWW: + case Qt::Key_Sleep: + case Qt::Key_LightBulb: + case Qt::Key_Shop: + case Qt::Key_History: + case Qt::Key_AddFavorite: + case Qt::Key_HotLinks: + case Qt::Key_BrightnessAdjust: + case Qt::Key_Finance: + case Qt::Key_Community: + case Qt::Key_AudioRewind: + case Qt::Key_BackForward: + case Qt::Key_ApplicationLeft: + case Qt::Key_ApplicationRight: + case Qt::Key_Book: + case Qt::Key_CD: + case Qt::Key_Clear: + case Qt::Key_ClearGrab: + case Qt::Key_Close: + case Qt::Key_Copy: + case Qt::Key_Cut: + case Qt::Key_Display: + case Qt::Key_DOS: + case Qt::Key_Documents: + case Qt::Key_Excel: + case Qt::Key_Explorer: + case Qt::Key_Game: + case Qt::Key_Go: + case Qt::Key_iTouch: + case Qt::Key_LogOff: + case Qt::Key_Market: + case Qt::Key_Meeting: + case Qt::Key_MenuKB: + case Qt::Key_MenuPB: + case Qt::Key_MySites: + case Qt::Key_News: + case Qt::Key_OfficeHome: + case Qt::Key_Option: + case Qt::Key_Paste: + case Qt::Key_Phone: + case Qt::Key_Reply: + case Qt::Key_Reload: + case Qt::Key_RotateWindows: + case Qt::Key_RotationPB: + case Qt::Key_RotationKB: + case Qt::Key_Save: + case Qt::Key_Send: + case Qt::Key_Spell: + case Qt::Key_SplitScreen: + case Qt::Key_Support: + case Qt::Key_TaskPane: + case Qt::Key_Terminal: + case Qt::Key_Tools: + case Qt::Key_Travel: + case Qt::Key_Video: + case Qt::Key_Word: + case Qt::Key_Xfer: + case Qt::Key_ZoomIn: + case Qt::Key_ZoomOut: + case Qt::Key_Away: + case Qt::Key_Messenger: + case Qt::Key_WebCam: + case Qt::Key_MailForward: + case Qt::Key_Pictures: + case Qt::Key_Music: + case Qt::Key_Battery: + case Qt::Key_Bluetooth: + case Qt::Key_WLAN: + case Qt::Key_UWB: + case Qt::Key_AudioForward: + case Qt::Key_AudioRepeat: + case Qt::Key_AudioRandomPlay: + case Qt::Key_Subtitle: + case Qt::Key_AudioCycleTrack: + case Qt::Key_Time: + case Qt::Key_Select: + case Qt::Key_View: + case Qt::Key_TopMenu: + case Qt::Key_Suspend: + case Qt::Key_Hibernate: + case Qt::Key_Launch0: + case Qt::Key_Launch1: + case Qt::Key_Launch2: + case Qt::Key_Launch3: + case Qt::Key_Launch4: + case Qt::Key_Launch5: + case Qt::Key_Launch6: + case Qt::Key_Launch7: + case Qt::Key_Launch8: + case Qt::Key_Launch9: + case Qt::Key_LaunchA: + case Qt::Key_LaunchB: + case Qt::Key_LaunchC: + case Qt::Key_LaunchD: + case Qt::Key_LaunchE: + case Qt::Key_LaunchF: + return true; + + default: + return false; + } +} + + +static bool isOkWhenModifierless(int key) +{ + //this whole function is a hack, but especially the first line of code + if (QKeySequence(key).toString().length() == 1) { + return false; + } + + switch (key) { + case Qt::Key_Return: + case Qt::Key_Space: + case Qt::Key_Tab: + case Qt::Key_Backtab: //does this ever happen? + case Qt::Key_Backspace: + case Qt::Key_Delete: + return false; + default: + return true; + } +} + +static QKeySequence appendToSequence(const QKeySequence &sequence, int key) { + std::array<int, 4> keys{sequence[0], sequence[1], sequence[2], sequence[3]}; + keys[sequence.count()] = key; + return QKeySequence(keys[0], keys[1], keys[2], keys[3]); +} + +class KeySequenceRecorderPrivate : public QObject { + Q_OBJECT +public: + KeySequenceRecorderPrivate(KeySequenceRecorder *q); + + void controlModifierlessTimeout(); + bool eventFilter(QObject *watched, QEvent *event) override; + void handleKeyPress(QKeyEvent *event); + void handleKeyRelease(QKeyEvent *event); + void finishRecording(); + + KeySequenceRecorder *q; + QKeySequence m_currentKeySequence; + QPointer<QWindow> m_window; + bool m_isRecording; + bool m_multiKeyShortcutsAllowed; + bool m_modifierlessAllowed; + + Qt::KeyboardModifiers m_currentModifiers; + QTimer m_modifierlessTimer; + std::unique_ptr<ShortcutInhibition> m_inhibition; +}; + +KeySequenceRecorderPrivate::KeySequenceRecorderPrivate(KeySequenceRecorder *q) + : QObject(q) + , q(q) +{ +} + +void KeySequenceRecorderPrivate::controlModifierlessTimeout() +{ + if (m_currentKeySequence != 0 && !m_currentModifiers) { + // No modifier key pressed currently. Start the timout + m_modifierlessTimer.start(600); + } else { + // A modifier is pressed. Stop the timeout + m_modifierlessTimer.stop(); + } +} + +bool KeySequenceRecorderPrivate::eventFilter(QObject *watched, QEvent *event) +{ + if (!m_isRecording) { + return QObject::eventFilter(watched, event); + } + + if (event->type() == QEvent::ShortcutOverride || event->type() == QEvent::ContextMenu) { + event->accept(); + return true; + } + if (event->type() == QEvent::KeyRelease) { + handleKeyRelease(static_cast<QKeyEvent*>(event)); + return true; + } + if (event->type() == QEvent::KeyPress) { + handleKeyPress(static_cast<QKeyEvent*>(event)); + return true; + } + return QObject::eventFilter(watched, event); +} + +void KeySequenceRecorderPrivate::handleKeyPress(QKeyEvent *event) +{ + + m_currentModifiers = event->modifiers() & modifierMask; + int key = event->key(); + switch (key) { + case -1: + qCWarning(KGUIADDONS_LOG) << "Got unknown key"; + // Old behavior was to stop recording here instead of continuing like this + return; + case 0: + break; + case Qt::Key_AltGr: + //or else we get unicode salad + break; + case Qt::Key_Super_L: + case Qt::Key_Super_R: + // Qt doesn't properly recognize Super_L/Super_R as MetaModifier + m_currentModifiers |= Qt::MetaModifier; + Q_FALLTHROUGH(); + case Qt::Key_Shift: + case Qt::Key_Control: + case Qt::Key_Alt: + case Qt::Key_Meta: + controlModifierlessTimeout(); + Q_EMIT q->currentKeySequenceChanged(); + break; + default: + if (m_currentKeySequence.count() == 0 && !(m_currentModifiers & ~Qt::ShiftModifier)) { + // It's the first key and no modifier pressed. Check if this is allowed + if (!(isOkWhenModifierless(key) || m_modifierlessAllowed)) { + // No it's not + return; + } + } + + // We now have a valid key press. + if ((key == Qt::Key_Backtab) && (m_currentModifiers & Qt::ShiftModifier)) { + key = Qt::Key_Tab | m_currentModifiers; + } else if (isShiftAsModifierAllowed(key)) { + key |= m_currentModifiers; + } else { + key |= (m_currentModifiers & ~Qt::ShiftModifier); + } + + m_currentKeySequence = appendToSequence(m_currentKeySequence, key); + Q_EMIT q->currentKeySequenceChanged(); + + if ((!m_multiKeyShortcutsAllowed) || (m_currentKeySequence.count() == 4)) { + finishRecording(); + break; + } + controlModifierlessTimeout(); + } + event->accept(); +} + +void KeySequenceRecorderPrivate::handleKeyRelease(QKeyEvent *event) +{ + Qt::KeyboardModifiers modifiers = event->modifiers() & modifierMask; + switch (event->key()) { + case -1: + return; + case Qt::Key_Super_L: + case Qt::Key_Super_R: + // Qt doesn't properly recognize Super_L/Super_R as MetaModifier + modifiers &= ~Qt::MetaModifier; + } + if ((modifiers & m_currentModifiers) < m_currentModifiers) { + m_currentModifiers = modifiers; + controlModifierlessTimeout(); + Q_EMIT q->currentKeySequenceChanged(); + } +} + +void KeySequenceRecorderPrivate::finishRecording() +{ + m_modifierlessTimer.stop(); + m_isRecording = false; + m_currentModifiers = Qt::NoModifier; + if (m_inhibition) { + m_inhibition->disableInhibition(); + } + Q_EMIT q->recordingChanged(); + Q_EMIT q->gotKeySequence(m_currentKeySequence); +} + +KeySequenceRecorder::KeySequenceRecorder(QWindow *window, QObject *parent) + : QObject(parent) + , d(new KeySequenceRecorderPrivate(this)) +{ + d->m_isRecording = false; + d->m_modifierlessAllowed = false; + d->m_multiKeyShortcutsAllowed = true; + + setWindow(window); + connect(&d->m_modifierlessTimer, &QTimer::timeout, d.get(), &KeySequenceRecorderPrivate::finishRecording); +} + +KeySequenceRecorder::~KeySequenceRecorder() noexcept +{ +} + +void KeySequenceRecorder::startRecording() +{ + if (!d->m_window) { + qCWarning(KGUIADDONS_LOG) << "Cannot record without a window"; + return; + } + d->m_isRecording = true; + d->m_currentKeySequence = QKeySequence(); + if (d->m_inhibition) { + d->m_inhibition->enableInhibition(); + } + Q_EMIT recordingChanged(); + Q_EMIT currentKeySequenceChanged(); +} + +bool KeySequenceRecorder::isRecording() const +{ + return d->m_isRecording; +} + +QKeySequence KeySequenceRecorder::currentKeySequence() const +{ + return d->m_isRecording ? appendToSequence(d->m_currentKeySequence, d->m_currentModifiers) : d->m_currentKeySequence; +} + +QWindow* KeySequenceRecorder::window() const +{ + return d->m_window; +} + +void KeySequenceRecorder::setWindow(QWindow *window) +{ + if (window == d->m_window) { + return; + } + + if (d->m_window) { + d->m_window->removeEventFilter(d.get()); + } + + if (window) { + window->installEventFilter(d.get()); + qCDebug(KGUIADDONS_LOG) << "listening for events in" << window; + } + + if (qApp->platformName() == QLatin1String("wayland")) { +#ifdef WITH_WAYLAND + d->m_inhibition.reset(new WaylandInhibition(window)); +#endif + } else { + d->m_inhibition.reset(new KeyboardGrabber(window)); + } + + d->m_window = window; + + Q_EMIT windowChanged(); +} + +bool KeySequenceRecorder::multiKeyShortcutsAllowed() const +{ + return d->m_multiKeyShortcutsAllowed; +} + +void KeySequenceRecorder::setMultiKeyShortcutsAllowed(bool allowed) +{ + if (allowed == d->m_multiKeyShortcutsAllowed) { + return; + } + d->m_multiKeyShortcutsAllowed = allowed; + Q_EMIT multiKeyShortcutsAllowedChanged(); +} + +bool KeySequenceRecorder::modifierlessAllowed() const +{ + return d->m_modifierlessAllowed; +} + +void KeySequenceRecorder::setModifierlessAllowed(bool allowed) +{ + if (allowed == d->m_modifierlessAllowed) { + return; + } + d->m_modifierlessAllowed = allowed; + Q_EMIT modifierlessAllowedChanged(); +} + +#include "keysequencerecorder.moc" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-5.76.0/src/recorder/keysequencerecorder.h new/kguiaddons-5.77.0/src/recorder/keysequencerecorder.h --- old/kguiaddons-5.76.0/src/recorder/keysequencerecorder.h 1970-01-01 01:00:00.000000000 +0100 +++ new/kguiaddons-5.77.0/src/recorder/keysequencerecorder.h 2020-12-05 11:07:55.000000000 +0100 @@ -0,0 +1,132 @@ +/* + SPDX-FileCopyrightText: 2001, 2002 Ellis Whitehead <[email protected]> + SPDX-FileCopyrightText: 2007 Andreas Hartmetz <[email protected]> + SPDX-FileCopyrightText: 2020 David Redondo <[email protected]> + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + + +#ifndef KSHORTCUTRECORDER_H +#define KSHORTCUTRECORDER_H + +#include <kguiaddons_export.h> + +#include <QKeySequence> +#include <QObject> + +#include <memory> + +class KeySequenceRecorderPrivate; + +class QWindow; + +/** + * @class KeySequenceRecorder keysequencerecorder.h KeySequenceRecorder + * + * @short Record a QKeySequence by listening to key events in a window. + * + * After calling startRecording key events in the set window will be captured until a valid + * QKeySequence has been recorded and gotKeySequence is emitted. See multiKeyShortcutsAllowed and + * modifierlessAllowed for what constitutes a valid key sequence. + * + * During recording any shortcuts are inhibited and cannot be triggered. Either by using the + * <a href="https://cgit.freedesktop.org/wayland/wayland-protocols/tree/unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml"> + * keyboard-shortcuts-inhibit protocol </a> on Wayland or grabbing the keyboard. + * + * For graphical elements that record key sequences and can optionally perform conflict checking + * against existing shortcuts see KKeySequenceWidget and KeySequenceItem. + * @since 5.77 + * @see KKeySequenceWidget, KeySequenceItem + */ + +class KGUIADDONS_EXPORT KeySequenceRecorder : public QObject +{ + Q_OBJECT + + /** + * Whether key events are currently recorded + */ + Q_PROPERTY(bool isRecording READ isRecording NOTIFY recordingChanged) + /** + * The recorded key sequence. + * After construction this is empty. + * + * During recording it is continiously updated with the newest user input. + * + * After recording it contains the last recorded QKeySequence + */ + Q_PROPERTY(QKeySequence currentKeySequence READ currentKeySequence NOTIFY currentKeySequenceChanged) + /** + * The window in which the key events are happening that should be recorded + */ + Q_PROPERTY(QWindow* window READ window WRITE setWindow NOTIFY windowChanged) + /** + * If key presses of "plain" keys without a modifier are considered to be a valid finished + * key combination. + * Plain keys include letter and symbol keys and text editing keys (Return, Space, Tab, + * Backspace, Delete). Other keys like F1, Cursor keys, Insert, PageDown will always work. + * + * By default this is `false`. + */ + Q_PROPERTY(bool modifierlessAllowed READ modifierlessAllowed WRITE setModifierlessAllowed NOTIFY modifierlessAllowedChanged) + /** Controls the amount of key combinations that are captured until recording stops and gotKeySequence + * is emitted. + * By default this is `true` and "Emacs-style" key sequences are recorded. Recording does not + * stop until four valid key combination have been recorded. Afterwards `currentKeySequence().count()` + * will be 4. + * + * Otherwise only one key combination is recorded before gotKeySequence is emitted with a + * QKeySequence with a `count()` of 1. + * @see QKeySequence + */ + Q_PROPERTY(bool multiKeyShortcutsAllowed READ multiKeyShortcutsAllowed WRITE setMultiKeyShortcutsAllowed NOTIFY multiKeyShortcutsAllowedChanged) +public: + /** + * Constructor. + * + * @par window The window whose key events will be recorded. + * @see window + */ + explicit KeySequenceRecorder(QWindow *window, QObject *parent = nullptr); + ~KeySequenceRecorder(); + + /** + * Start recording. + * Calling startRecording when window() is `nullptr` has no effect. + */ + void Q_INVOKABLE startRecording(); + + bool isRecording() const; + + QKeySequence currentKeySequence() const; + + QWindow* window() const; + void setWindow(QWindow *window); + + bool multiKeyShortcutsAllowed() const; + void setMultiKeyShortcutsAllowed(bool allowed); + + void setModifierlessAllowed(bool allowed); + bool modifierlessAllowed() const; + +Q_SIGNALS: + /** + * This signal is emitted when a key sequence has been recorded. + * + * Compared to currentKeySequenceChanged and currentKeySequence this is signal is not emmitted + * continiously during recording but only after recording has finished. + */ + void gotKeySequence(const QKeySequence &keySequence); + + void recordingChanged(); + void windowChanged(); + void currentKeySequenceChanged(); + void multiKeyShortcutsAllowedChanged(); + void modifierlessAllowedChanged(); +private: + friend class KeySequenceRecorderPrivate; + std::unique_ptr<KeySequenceRecorderPrivate> d; +}; + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-5.76.0/src/recorder/shortcutinhibition_p.h new/kguiaddons-5.77.0/src/recorder/shortcutinhibition_p.h --- old/kguiaddons-5.76.0/src/recorder/shortcutinhibition_p.h 1970-01-01 01:00:00.000000000 +0100 +++ new/kguiaddons-5.77.0/src/recorder/shortcutinhibition_p.h 2020-12-05 11:07:55.000000000 +0100 @@ -0,0 +1,19 @@ +/* + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL + SPDX-FileCopyrightText: 2020 David Redondo <[email protected]> +*/ + +#ifndef SHORTCUTINHIBITION_H +#define SHORTCUTINHIBITION_H + +class QWindow; + +class ShortcutInhibition { +public: + virtual ~ShortcutInhibition(){} + virtual void enableInhibition() = 0; + virtual void disableInhibition() = 0; + virtual bool shortcutsAreInhibited() const = 0; +}; + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-5.76.0/src/recorder/waylandinhibition.cpp new/kguiaddons-5.77.0/src/recorder/waylandinhibition.cpp --- old/kguiaddons-5.76.0/src/recorder/waylandinhibition.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/kguiaddons-5.77.0/src/recorder/waylandinhibition.cpp 2020-12-05 11:07:55.000000000 +0100 @@ -0,0 +1,104 @@ +/* + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL + SPDX-FileCopyrightText: 2020 David Redondo <[email protected]> +*/ + +#include "waylandinhibition_p.h" + +#include <QGuiApplication> +#include <qpa/qplatformnativeinterface.h> +#include <QtWaylandClient/QWaylandClientExtensionTemplate> + +#include "qwayland-keyboard-shortcuts-inhibit-unstable-v1.h" + +class ShortcutsInhibitManager + : public QWaylandClientExtensionTemplate<ShortcutsInhibitManager> + , public QtWayland::zwp_keyboard_shortcuts_inhibit_manager_v1 +{ +public: + ShortcutsInhibitManager() + : QWaylandClientExtensionTemplate<ShortcutsInhibitManager>(1) + { + // QWaylandClientExtensionTemplate invokes this with a QueuedConnection but we want shortcuts + // to be inhibited immediately. + QMetaObject::invokeMethod(this, "addRegistryListener"); + } + ~ShortcutsInhibitManager() + { + if (isInitialized()) { + destroy(); + } + } +}; + +class ShortcutsInhibitor : public QtWayland::zwp_keyboard_shortcuts_inhibitor_v1 +{ +public: + ShortcutsInhibitor(::zwp_keyboard_shortcuts_inhibitor_v1 *id) + : QtWayland::zwp_keyboard_shortcuts_inhibitor_v1(id) + { + } + + ~ShortcutsInhibitor() + { + destroy(); + } + + void zwp_keyboard_shortcuts_inhibitor_v1_active() override + { + m_active = true; + } + + void zwp_keyboard_shortcuts_inhibitor_v1_inactive() override + { + m_active = false; + } + + bool isActive() const + { + return m_active; + } + +private: + bool m_active = false; +}; + +WaylandInhibition::WaylandInhibition(QWindow *window) + : ShortcutInhibition() + , m_manager(new ShortcutsInhibitManager) + , m_window(window) +{ +} + +WaylandInhibition::~WaylandInhibition() = default; + +bool WaylandInhibition::shortcutsAreInhibited() const +{ + return m_inhibitor && m_inhibitor->isActive(); +} + +void WaylandInhibition::enableInhibition() +{ + if (m_inhibitor || !m_manager->isActive()) { + return; + } + QPlatformNativeInterface *nativeInterface = qApp->platformNativeInterface(); + if (!nativeInterface) { + return; + } + auto seat = static_cast<wl_seat*>(nativeInterface->nativeResourceForIntegration("wl_seat")); + auto surface = static_cast<wl_surface*>(nativeInterface->nativeResourceForWindow("surface", m_window)); + if (!seat || !surface) { + return; + } + m_inhibitor.reset(new ShortcutsInhibitor(m_manager->inhibit_shortcuts(surface, seat))); +} + +void WaylandInhibition::disableInhibition() +{ + if (!m_inhibitor) { + return; + } + m_inhibitor.reset(); +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-5.76.0/src/recorder/waylandinhibition_p.h new/kguiaddons-5.77.0/src/recorder/waylandinhibition_p.h --- old/kguiaddons-5.76.0/src/recorder/waylandinhibition_p.h 1970-01-01 01:00:00.000000000 +0100 +++ new/kguiaddons-5.77.0/src/recorder/waylandinhibition_p.h 2020-12-05 11:07:55.000000000 +0100 @@ -0,0 +1,31 @@ +/* + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL + SPDX-FileCopyrightText: 2020 David Redondo <[email protected]> +*/ + +#ifndef WAYLANDSHORTCUTINHIBITOR_H +#define WAYLANDSHORTCUTINHIBITOR_H + +#include "shortcutinhibition_p.h" + +#include <memory> + +class ShortcutsInhibitManager; +class ShortcutsInhibitor; + +class WaylandInhibition : public ShortcutInhibition +{ +public: + explicit WaylandInhibition(QWindow *window); + ~WaylandInhibition() override; + bool shortcutsAreInhibited() const override; + void enableInhibition() override; + void disableInhibition() override; +private: + + std::unique_ptr<ShortcutsInhibitManager> m_manager; + std::unique_ptr<ShortcutsInhibitor> m_inhibitor; + QWindow *m_window; +}; + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-5.76.0/tests/kmodifierkeyinfotest.cpp new/kguiaddons-5.77.0/tests/kmodifierkeyinfotest.cpp --- old/kguiaddons-5.76.0/tests/kmodifierkeyinfotest.cpp 2020-11-07 12:37:58.000000000 +0100 +++ new/kguiaddons-5.77.0/tests/kmodifierkeyinfotest.cpp 2020-12-05 11:07:55.000000000 +0100 @@ -120,8 +120,6 @@ layout->addLayout(hlayout); } - setLayout(layout); - connect(&m_lock, &KModifierKeyInfo::keyPressed, this, &TestWidget::keyPressed); connect(&m_lock, &KModifierKeyInfo::keyLatched, _______________________________________________ openSUSE Commits mailing list -- [email protected] To unsubscribe, email [email protected] List Netiquette: https://en.opensuse.org/openSUSE:Mailing_list_netiquette List Archives: https://lists.opensuse.org/archives/list/[email protected]
