[effects/zoom] Implement focus tracking with QAccessibilityClient
Currently, the focus tracking functionality in the zoom effect does not work because it relies on kaccessibleapp, which is dead. Luckily for us, there is a library called libqaccessibilityclient that provides a way to monitor focus changes. BUG: 421234
This commit is contained in:
parent
7226e75bc8
commit
c1ea0412a4
10 changed files with 216 additions and 83 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
91
effects/zoom/accessibilityintegration.cpp
Normal file
91
effects/zoom/accessibilityintegration.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#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
|
53
effects/zoom/accessibilityintegration.h
Normal file
53
effects/zoom/accessibilityintegration.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <qaccessibilityclient/registry.h>
|
||||
|
||||
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
|
|
@ -23,11 +23,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
// KConfigSkeleton
|
||||
#include "zoomconfig.h"
|
||||
|
||||
#if HAVE_ACCESSIBILITY
|
||||
#include "accessibilityintegration.h"
|
||||
#endif
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QStyle>
|
||||
#include <QVector2D>
|
||||
#include <QDBusConnection>
|
||||
#include <kstandardaction.h>
|
||||
#include <KConfigGroup>
|
||||
#include <KGlobalAccel>
|
||||
|
@ -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
|
||||
|
|
|
@ -22,6 +22,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#ifndef KWIN_ZOOM_H
|
||||
#define KWIN_ZOOM_H
|
||||
|
||||
#include <config-kwin.h>
|
||||
|
||||
#include <kwineffects.h>
|
||||
#include <QTime>
|
||||
#include <QTimeLine>
|
||||
|
@ -29,6 +31,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
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;
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
<entry name="EnableFocusTracking" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="EnableFollowFocus" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="FocusDelay" type="UInt">
|
||||
<default>350</default>
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>304</width>
|
||||
<height>212</height>
|
||||
<height>288</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
|
@ -63,26 +63,13 @@
|
|||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Enable tracking of the focused location. This needs QAccessible to be enabled per application ("export QT_ACCESSIBILITY=1").</string>
|
||||
<string>Enable tracking of the focused location. This needs QAccessible to be enabled per application ("export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1").</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable Focus Tracking</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="kcfg_EnableFollowFocus">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>When the focus changes, move the zoom area to the focused location.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Follow Focus</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
|
@ -164,16 +151,13 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="KShortcutsEditor" name="editor" native="true">
|
||||
<widget class="KShortcutsEditor" name="editor">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="actionTypes">
|
||||
<enum>KShortcutsEditor::GlobalAction</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -182,7 +166,7 @@
|
|||
<customwidget>
|
||||
<class>KShortcutsEditor</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">KShortcutsEditor</header>
|
||||
<header>kshortcutseditor.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
|
@ -191,25 +175,7 @@
|
|||
<tabstop>kcfg_MousePointer</tabstop>
|
||||
<tabstop>kcfg_MouseTracking</tabstop>
|
||||
<tabstop>kcfg_EnableFocusTracking</tabstop>
|
||||
<tabstop>kcfg_EnableFollowFocus</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>kcfg_EnableFocusTracking</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>kcfg_EnableFollowFocus</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>152</x>
|
||||
<y>73</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>152</x>
|
||||
<y>98</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
Loading…
Reference in a new issue