diff --git a/CMakeLists.txt b/CMakeLists.txt index f941657084..b86bece6e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -300,6 +300,15 @@ set_package_properties(hwdata PROPERTIES URL "https://github.com/vcrhonek/hwdata" ) +find_package(QAccessibilityClient CONFIG) +set_package_properties(QAccessibilityClient PROPERTIES + URL "https://www.kde.org" + DESCRIPTION "KDE client-side accessibility library" + TYPE OPTIONAL + PURPOSE "Required to enable accessibility features" +) +set(HAVE_ACCESSIBILITY ${QAccessibilityClient_FOUND}) + include(ECMQMLModules) ecm_find_qmlmodule(QtQuick 2.3) ecm_find_qmlmodule(QtQuick.Controls 1.2) diff --git a/config-kwin.h.cmake b/config-kwin.h.cmake index 90efb3e58f..9e900d65fa 100644 --- a/config-kwin.h.cmake +++ b/config-kwin.h.cmake @@ -25,6 +25,7 @@ #cmakedefine01 HAVE_BREEZE_DECO #cmakedefine01 HAVE_LIBCAP #cmakedefine01 HAVE_SCHED_RESET_ON_FORK +#cmakedefine01 HAVE_ACCESSIBILITY #if HAVE_BREEZE_DECO #define BREEZE_KDECORATION_PLUGIN_ID "${BREEZE_KDECORATION_PLUGIN_ID}" #endif diff --git a/effects/CMakeLists.txt b/effects/CMakeLists.txt index 386812d78b..0ad5b212cb 100644 --- a/effects/CMakeLists.txt +++ b/effects/CMakeLists.txt @@ -3,6 +3,10 @@ add_definitions(-DTRANSLATION_DOMAIN=\"kwin_effects\" -DEFFECT_BUILTINS) include_directories(${KWin_SOURCE_DIR}) # for xcbutils.h +if (HAVE_ACCESSIBILITY) + include_directories(${QACCESSIBILITYCLIENT_INCLUDE_DIR}) +endif() + set(kwin_effect_OWN_LIBS kwineffects ) @@ -21,6 +25,10 @@ set(kwin_effect_KDE_LIBS KF5::WindowSystem ) +if (HAVE_ACCESSIBILITY) + set(kwin_effect_KDE_LIBS ${kwin_effect_KDE_LIBS} ${QACCESSIBILITYCLIENT_LIBRARY}) +endif() + set(kwin_effect_QT_LIBS Qt5::Concurrent Qt5::DBus @@ -104,6 +112,13 @@ set(kwin4_effect_builtins_sources zoom/zoom.cpp ) +if (HAVE_ACCESSIBILITY) + set(kwin4_effect_builtins_sources + zoom/accessibilityintegration.cpp + ${kwin4_effect_builtins_sources} + ) +endif() + qt5_add_resources(kwin4_effect_builtins_sources shaders.qrc) kconfig_add_kcfg_files(kwin4_effect_builtins_sources diff --git a/effects/zoom/accessibilityintegration.cpp b/effects/zoom/accessibilityintegration.cpp new file mode 100644 index 0000000000..088c7c407a --- /dev/null +++ b/effects/zoom/accessibilityintegration.cpp @@ -0,0 +1,91 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2020 Vlad Zahorodnii + +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 2 of the License, or +(at your option) 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 "accessibilityintegration.h" + +using namespace QAccessibleClient; // Whatever, sue me... + +namespace KWin +{ + +ZoomAccessibilityIntegration::ZoomAccessibilityIntegration(QObject *parent) + : QObject(parent) +{ +} + +void ZoomAccessibilityIntegration::setFocusTrackingEnabled(bool enabled) +{ + if (m_isFocusTrackingEnabled == enabled) { + return; + } + m_isFocusTrackingEnabled = enabled; + updateAccessibilityRegistry(); +} + +bool ZoomAccessibilityIntegration::isFocusTrackingEnabled() const +{ + return m_isFocusTrackingEnabled; +} + +void ZoomAccessibilityIntegration::updateAccessibilityRegistry() +{ + Registry::EventListeners eventListeners = Registry::NoEventListeners; + + if (isFocusTrackingEnabled()) { + eventListeners |= Registry::Focus; + } + + if (eventListeners == Registry::NoEventListeners) { + destroyAccessibilityRegistry(); + return; + } + if (!m_accessibilityRegistry) { + createAccessibilityRegistry(); + } + + m_accessibilityRegistry->subscribeEventListeners(eventListeners); +} + +void ZoomAccessibilityIntegration::createAccessibilityRegistry() +{ + m_accessibilityRegistry = new Registry(this); + + connect(m_accessibilityRegistry, &Registry::focusChanged, + this, &ZoomAccessibilityIntegration::slotFocusChanged); +} + +void ZoomAccessibilityIntegration::destroyAccessibilityRegistry() +{ + if (!m_accessibilityRegistry) { + return; + } + + disconnect(m_accessibilityRegistry, nullptr, this, nullptr); + + m_accessibilityRegistry->deleteLater(); + m_accessibilityRegistry = nullptr; +} + +void ZoomAccessibilityIntegration::slotFocusChanged(const AccessibleObject &object) +{ + emit focusPointChanged(object.focusPoint()); +} + +} // namespace KWin diff --git a/effects/zoom/accessibilityintegration.h b/effects/zoom/accessibilityintegration.h new file mode 100644 index 0000000000..99942177f4 --- /dev/null +++ b/effects/zoom/accessibilityintegration.h @@ -0,0 +1,53 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2020 Vlad Zahorodnii + +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 2 of the License, or +(at your option) 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 . +*********************************************************************/ + +#pragma once + +#include + +namespace KWin +{ + +class ZoomAccessibilityIntegration : public QObject +{ + Q_OBJECT + +public: + explicit ZoomAccessibilityIntegration(QObject *parent = nullptr); + + void setFocusTrackingEnabled(bool enabled); + bool isFocusTrackingEnabled() const; + +Q_SIGNALS: + void focusPointChanged(const QPoint &point); + +private Q_SLOTS: + void slotFocusChanged(const QAccessibleClient::AccessibleObject &object); + +private: + void createAccessibilityRegistry(); + void destroyAccessibilityRegistry(); + void updateAccessibilityRegistry(); + + QAccessibleClient::Registry *m_accessibilityRegistry = nullptr; + bool m_isFocusTrackingEnabled = false; +}; + +} // namespace KWin diff --git a/effects/zoom/zoom.cpp b/effects/zoom/zoom.cpp index d884262777..95231a0a33 100644 --- a/effects/zoom/zoom.cpp +++ b/effects/zoom/zoom.cpp @@ -23,11 +23,14 @@ along with this program. If not, see . // KConfigSkeleton #include "zoomconfig.h" +#if HAVE_ACCESSIBILITY +#include "accessibilityintegration.h" +#endif + #include #include #include #include -#include #include #include #include @@ -49,8 +52,6 @@ ZoomEffect::ZoomEffect() , polling(false) , zoomFactor(1.25) , mouseTracking(MouseTrackingProportional) - , enableFocusTracking(false) - , followFocus(true) , mousePointer(MousePointerScale) , focusDelay(350) // in milliseconds , imageWidth(0) @@ -133,6 +134,11 @@ ZoomEffect::ZoomEffect() connect(&timeline, &QTimeLine::frameChanged, this, &ZoomEffect::timelineFrameChanged); connect(effects, &EffectsHandler::mouseChanged, this, &ZoomEffect::slotMouseChanged); +#if HAVE_ACCESSIBILITY + m_accessibilityIntegration = new ZoomAccessibilityIntegration(this); + connect(m_accessibilityIntegration, &ZoomAccessibilityIntegration::focusPointChanged, this, &ZoomEffect::moveFocus); +#endif + source_zoom = -1; // used to trigger initialZoom reading reconfigure(ReconfigureAll); } @@ -146,6 +152,15 @@ ZoomEffect::~ZoomEffect() ZoomConfig::self()->save(); } +bool ZoomEffect::isFocusTrackingEnabled() const +{ +#if HAVE_ACCESSIBILITY + return m_accessibilityIntegration->isFocusTrackingEnabled(); +#else + return false; +#endif +} + void ZoomEffect::showCursor() { if (isMouseHidden) { @@ -215,27 +230,10 @@ void ZoomEffect::reconfigure(ReconfigureFlags) mousePointer = MousePointerType(ZoomConfig::mousePointer()); // Track moving of the mouse. mouseTracking = MouseTrackingType(ZoomConfig::mouseTracking()); +#if HAVE_ACCESSIBILITY // Enable tracking of the focused location. - bool _enableFocusTracking = ZoomConfig::enableFocusTracking(); - if (enableFocusTracking != _enableFocusTracking) { - enableFocusTracking = _enableFocusTracking; - if (QDBusConnection::sessionBus().isConnected()) { - if (enableFocusTracking) - QDBusConnection::sessionBus().connect(QStringLiteral("org.kde.kaccessibleapp"), - QStringLiteral("/Adaptor"), - QStringLiteral("org.kde.kaccessibleapp.Adaptor"), - QStringLiteral("focusChanged"), - this, SLOT(focusChanged(int,int,int,int,int,int))); - else - QDBusConnection::sessionBus().disconnect(QStringLiteral("org.kde.kaccessibleapp"), - QStringLiteral("/Adaptor"), - QStringLiteral("org.kde.kaccessibleapp.Adaptor"), - QStringLiteral("focusChanged"), - this, SLOT(focusChanged(int,int,int,int,int,int))); - } - } - // When the focus changes, move the zoom area to the focused location. - followFocus = ZoomConfig::enableFollowFocus(); + m_accessibilityIntegration->setFocusTrackingEnabled(ZoomConfig::enableFocusTracking()); +#endif // The time in milliseconds to wait before a focus-event takes away a mouse-move. focusDelay = qMax(uint(0), ZoomConfig::focusDelay()); // The factor the zoom-area will be moved on touching an edge on push-mode or using the navigation KAction's. @@ -316,7 +314,7 @@ void ZoomEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData& d } // use the focusPoint if focus tracking is enabled - if (enableFocusTracking && followFocus) { + if (isFocusTrackingEnabled()) { bool acceptFocus = true; if (mouseTracking != MouseTrackingDisabled && focusDelay > 0) { // Wait some time for the mouse before doing the switch. This serves as threshold @@ -513,16 +511,13 @@ void ZoomEffect::slotMouseChanged(const QPoint& pos, const QPoint& old, Qt::Mous } } -void ZoomEffect::focusChanged(int px, int py, int rx, int ry, int rwidth, int rheight) +void ZoomEffect::moveFocus(const QPoint &point) { if (zoom == 1.0) return; - const QSize screenSize = effects->virtualScreenSize(); - focusPoint = (px >= 0 && py >= 0) ? QPoint(px, py) : QPoint(rx + qMax(0, (qMin(screenSize.width(), rwidth) / 2) - 60), ry + qMax(0, (qMin(screenSize.height(), rheight) / 2) - 60)); - if (enableFocusTracking) { - lastFocusEvent = QTime::currentTime(); - effects->addRepaintFull(); - } + focusPoint = point; + lastFocusEvent = QTime::currentTime(); + effects->addRepaintFull(); } bool ZoomEffect::isActive() const diff --git a/effects/zoom/zoom.h b/effects/zoom/zoom.h index 61fe5ee29b..2c7bff41a0 100644 --- a/effects/zoom/zoom.h +++ b/effects/zoom/zoom.h @@ -22,6 +22,8 @@ along with this program. If not, see . #ifndef KWIN_ZOOM_H #define KWIN_ZOOM_H +#include + #include #include #include @@ -29,6 +31,10 @@ along with this program. If not, see . namespace KWin { +#if HAVE_ACCESSIBILITY +class ZoomAccessibilityIntegration; +#endif + class GLTexture; class XRenderPicture; @@ -39,8 +45,7 @@ class ZoomEffect Q_PROPERTY(qreal zoomFactor READ configuredZoomFactor) Q_PROPERTY(int mousePointer READ configuredMousePointer) Q_PROPERTY(int mouseTracking READ configuredMouseTracking) - Q_PROPERTY(bool enableFocusTracking READ isEnableFocusTracking) - Q_PROPERTY(bool followFocus READ isFollowFocus) + Q_PROPERTY(bool focusTrackingEnabled READ isFocusTrackingEnabled) Q_PROPERTY(int focusDelay READ configuredFocusDelay) Q_PROPERTY(qreal moveFactor READ configuredMoveFactor) Q_PROPERTY(qreal targetZoom READ targetZoom) @@ -62,12 +67,7 @@ public: int configuredMouseTracking() const { return mouseTracking; } - bool isEnableFocusTracking() const { - return enableFocusTracking; - } - bool isFollowFocus() const { - return followFocus; - } + bool isFocusTrackingEnabled() const; int configuredFocusDelay() const { return focusDelay; } @@ -89,7 +89,7 @@ private Q_SLOTS: void moveMouseToFocus(); void moveMouseToCenter(); void timelineFrameChanged(int frame); - void focusChanged(int px, int py, int rx, int ry, int rwidth, int rheight); + void moveFocus(const QPoint &point); void slotMouseChanged(const QPoint& pos, const QPoint& old, Qt::MouseButtons buttons, Qt::MouseButtons oldbuttons, Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers); @@ -99,6 +99,9 @@ private: void hideCursor(); void moveZoom(int x, int y); private: +#if HAVE_ACCESSIBILITY + ZoomAccessibilityIntegration *m_accessibilityIntegration = nullptr; +#endif double zoom; double target_zoom; double source_zoom; @@ -106,8 +109,6 @@ private: double zoomFactor; enum MouseTrackingType { MouseTrackingProportional = 0, MouseTrackingCentred = 1, MouseTrackingPush = 2, MouseTrackingDisabled = 3 }; MouseTrackingType mouseTracking; - bool enableFocusTracking; - bool followFocus; enum MousePointerType { MousePointerScale = 0, MousePointerKeep = 1, MousePointerHide = 2 }; MousePointerType mousePointer; int focusDelay; diff --git a/effects/zoom/zoom.kcfg b/effects/zoom/zoom.kcfg index c706906a7a..af37db08e6 100644 --- a/effects/zoom/zoom.kcfg +++ b/effects/zoom/zoom.kcfg @@ -17,8 +17,6 @@ false - - true 350 diff --git a/effects/zoom/zoom_config.cpp b/effects/zoom/zoom_config.cpp index 78dafd2bff..9fc1f8610e 100644 --- a/effects/zoom/zoom_config.cpp +++ b/effects/zoom/zoom_config.cpp @@ -60,6 +60,10 @@ ZoomEffectConfig::ZoomEffectConfig(QWidget* parent, const QVariantList& args) : connect(m_ui->editor, &KShortcutsEditor::keyChange, this, &ZoomEffectConfig::markAsChanged); +#if !HAVE_ACCESSIBILITY + m_ui->kcfg_EnableFocusTracking->setVisible(false); +#endif + // Shortcut config. The shortcut belongs to the component "kwin"! KActionCollection *actionCollection = new KActionCollection(this, QStringLiteral("kwin")); actionCollection->setComponentDisplayName(i18n("KWin")); diff --git a/effects/zoom/zoom_config.ui b/effects/zoom/zoom_config.ui index 3fb45bd712..5b387b2a4e 100644 --- a/effects/zoom/zoom_config.ui +++ b/effects/zoom/zoom_config.ui @@ -7,7 +7,7 @@ 0 0 304 - 212 + 288 @@ -63,26 +63,13 @@ - Enable tracking of the focused location. This needs QAccessible to be enabled per application ("export QT_ACCESSIBILITY=1"). + Enable tracking of the focused location. This needs QAccessible to be enabled per application ("export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1"). Enable Focus Tracking - - - - false - - - When the focus changes, move the zoom area to the focused location. - - - Follow Focus - - - @@ -164,16 +151,13 @@ - + 0 0 - - KShortcutsEditor::GlobalAction - @@ -182,7 +166,7 @@ KShortcutsEditor QWidget -
KShortcutsEditor
+
kshortcutseditor.h
1
@@ -191,25 +175,7 @@ kcfg_MousePointer kcfg_MouseTracking kcfg_EnableFocusTracking - kcfg_EnableFollowFocus - - - kcfg_EnableFocusTracking - toggled(bool) - kcfg_EnableFollowFocus - setEnabled(bool) - - - 152 - 73 - - - 152 - 98 - - - - +