Merge branch 'Plasma/5.8'

remotes/origin/bshah/hwcomposer_testing
Martin Gräßlin 10 years ago
commit 196ac5eb38
  1. 33
      autotests/integration/globalshortcuts_test.cpp
  2. 1
      autotests/integration/kwin_wayland_test.cpp
  3. 71
      autotests/integration/modifier_only_shortcut_test.cpp
  4. 63
      keyboard_input.cpp
  5. 6
      keyboard_input.h
  6. 4
      useractions.h

@ -23,9 +23,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "platform.h"
#include "screens.h"
#include "shell_client.h"
#include "useractions.h"
#include "wayland_server.h"
#include "workspace.h"
#include <KWayland/Client/shell.h>
#include <KWayland/Client/surface.h>
#include <KWayland/Server/seat_interface.h>
#include <KGlobalAccel>
@ -46,6 +49,7 @@ private Q_SLOTS:
void testConsumedShift();
void testRepeatedTrigger();
void testUserActionsMenu();
};
void GlobalShortcutsTest::initTestCase()
@ -67,12 +71,14 @@ void GlobalShortcutsTest::initTestCase()
void GlobalShortcutsTest::init()
{
QVERIFY(Test::setupWaylandConnection(s_socketName));
screens()->setCurrent(0);
KWin::Cursor::setPos(QPoint(640, 512));
}
void GlobalShortcutsTest::cleanup()
{
Test::destroyWaylandConnection();
}
void GlobalShortcutsTest::testConsumedShift()
@ -127,7 +133,6 @@ void GlobalShortcutsTest::testRepeatedTrigger()
QVERIFY(triggeredSpy.wait());
// now release the key
kwinApp()->platform()->keyboardKeyReleased(KEY_5, timestamp++);
QEXPECT_FAIL("", "BUG 369091", Continue);
QVERIFY(!triggeredSpy.wait(500));
kwinApp()->platform()->keyboardKeyReleased(KEY_WAKEUP, timestamp++);
@ -137,5 +142,31 @@ void GlobalShortcutsTest::testRepeatedTrigger()
kwinApp()->platform()->keyboardKeyReleased(KEY_LEFTSHIFT, timestamp++);
}
void GlobalShortcutsTest::testUserActionsMenu()
{
// this test tries to trigger the user actions menu with Alt+F3
// the problem here is that pressing F3 consumes modifiers as it's part of the
// Ctrl+alt+F3 keysym for vt switching. xkbcommon considers all modifiers as consumed
// which a transformation to any keysym would cause
// for more information see:
// https://bugs.freedesktop.org/show_bug.cgi?id=92818
// https://github.com/xkbcommon/libxkbcommon/issues/17
// first create a window
QScopedPointer<Surface> surface(Test::createSurface());
QScopedPointer<ShellSurface> shellSurface(Test::createShellSurface(surface.data()));
auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
QVERIFY(c);
QVERIFY(c->isActive());
quint32 timestamp = 0;
QVERIFY(!workspace()->userActionsMenu()->isShown());
kwinApp()->platform()->keyboardKeyPressed(KEY_LEFTALT, timestamp++);
kwinApp()->platform()->keyboardKeyPressed(KEY_F3, timestamp++);
kwinApp()->platform()->keyboardKeyReleased(KEY_F3, timestamp++);
QTRY_VERIFY(workspace()->userActionsMenu()->isShown());
kwinApp()->platform()->keyboardKeyReleased(KEY_LEFTALT, timestamp++);
}
WAYLANDTEST_MAIN(GlobalShortcutsTest)
#include "globalshortcuts_test.moc"

@ -46,6 +46,7 @@ static void readDisplay(int pipe);
WaylandTestApplication::WaylandTestApplication(int &argc, char **argv)
: Application(OperationModeXwayland, argc, argv)
{
QStandardPaths::setTestModeEnabled(true);
#ifdef KWIN_BUILD_ACTIVITIES
setUseKActivities(false);
#endif

@ -49,6 +49,8 @@ private Q_SLOTS:
void testTrigger_data();
void testTrigger();
void testCapsLock();
void testGlobalShortcutsDisabled_data();
void testGlobalShortcutsDisabled();
};
class Target : public QObject
@ -288,5 +290,74 @@ void ModifierOnlyShortcutTest::testCapsLock()
QCOMPARE(triggeredSpy.count(), 1);
}
void ModifierOnlyShortcutTest::testGlobalShortcutsDisabled_data()
{
QTest::addColumn<QStringList>("metaConfig");
QTest::addColumn<QStringList>("altConfig");
QTest::addColumn<QStringList>("controlConfig");
QTest::addColumn<QStringList>("shiftConfig");
QTest::addColumn<int>("modifier");
const QStringList trigger = QStringList{s_serviceName, s_path, s_serviceName, QStringLiteral("shortcut")};
const QStringList e = QStringList();
QTest::newRow("leftMeta") << trigger << e << e << e << KEY_LEFTMETA;
QTest::newRow("rightMeta") << trigger << e << e << e << KEY_RIGHTMETA;
QTest::newRow("leftAlt") << e << trigger << e << e << KEY_LEFTALT;
QTest::newRow("rightAlt") << e << trigger << e << e << KEY_RIGHTALT;
QTest::newRow("leftControl") << e << e << trigger << e << KEY_LEFTCTRL;
QTest::newRow("rightControl") << e << e << trigger << e << KEY_RIGHTCTRL;
QTest::newRow("leftShift") << e << e << e << trigger << KEY_LEFTSHIFT;
QTest::newRow("rightShift") << e << e << e << trigger <<KEY_RIGHTSHIFT;
}
void ModifierOnlyShortcutTest::testGlobalShortcutsDisabled()
{
// this test verifies that when global shortcuts are disabled inside KWin (e.g. through a window rule)
// the modifier only shortcuts do not trigger.
// see BUG: 370146
Target target;
QSignalSpy triggeredSpy(&target, &Target::shortcutTriggered);
QVERIFY(triggeredSpy.isValid());
KConfigGroup group = kwinApp()->config()->group("ModifierOnlyShortcuts");
QFETCH(QStringList, metaConfig);
QFETCH(QStringList, altConfig);
QFETCH(QStringList, shiftConfig);
QFETCH(QStringList, controlConfig);
group.writeEntry("Meta", metaConfig);
group.writeEntry("Alt", altConfig);
group.writeEntry("Shift", shiftConfig);
group.writeEntry("Control", controlConfig);
group.sync();
workspace()->slotReconfigure();
// trigger once to verify the shortcut works
quint32 timestamp = 1;
QFETCH(int, modifier);
QVERIFY(!workspace()->globalShortcutsDisabled());
kwinApp()->platform()->keyboardKeyPressed(modifier, timestamp++);
kwinApp()->platform()->keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 1);
triggeredSpy.clear();
// now disable global shortcuts
workspace()->disableGlobalShortcutsForClient(true);
QVERIFY(workspace()->globalShortcutsDisabled());
// Should not get triggered
kwinApp()->platform()->keyboardKeyPressed(modifier, timestamp++);
kwinApp()->platform()->keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 0);
triggeredSpy.clear();
// enable again
workspace()->disableGlobalShortcutsForClient(false);
QVERIFY(!workspace()->globalShortcutsDisabled());
// should get triggered again
kwinApp()->platform()->keyboardKeyPressed(modifier, timestamp++);
kwinApp()->platform()->keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 1);
}
WAYLANDTEST_MAIN(ModifierOnlyShortcutTest)
#include "modifier_only_shortcut_test.moc"

@ -310,7 +310,8 @@ void Xkb::updateKey(uint32_t key, InputRedirection::KeyboardKeyState state)
} else {
m_modOnlyShortcut.pressCount--;
if (m_modOnlyShortcut.pressCount == 0 &&
m_modifiers == Qt::NoModifier) {
m_modifiers == Qt::NoModifier &&
!workspace()->globalShortcutsDisabled()) {
if (m_modOnlyShortcut.modifier != Qt::NoModifier) {
const auto list = options->modifierOnlyDBusShortcut(m_modOnlyShortcut.modifier);
if (list.size() >= 4) {
@ -403,6 +404,24 @@ Qt::KeyboardModifiers Xkb::modifiersRelevantForGlobalShortcuts() const
if (xkb_state_mod_index_is_active(m_state, m_metaModifier, XKB_STATE_MODS_EFFECTIVE) == 1) {
mods |= Qt::MetaModifier;
}
// workaround xkbcommon limitation concerning consumed modifiers
// if a key could be turned into a keysym with a modifier xkbcommon
// considers the modifier as consumed even if not pressed
// e.g. alt+F3 considers alt as consumed as there is a keysym generated
// with ctrl+alt+F3 (vt switching)
// For more information see:
// https://bugs.freedesktop.org/show_bug.cgi?id=92818
// https://github.com/xkbcommon/libxkbcommon/issues/17
// the workaround is to not consider the modifiers as consumed
// if they are not a currently
// this might have other side effects, though. The only proper way to
// handle this is through new API in xkbcommon which doesn't exist yet
if (m_consumedModifiers & ~m_modifiers) {
return mods;
}
return mods & ~m_consumedModifiers;
}
@ -463,17 +482,25 @@ KeyboardInputRedirection::KeyboardInputRedirection(InputRedirection *parent)
{
}
KeyboardInputRedirection::~KeyboardInputRedirection()
{
qDeleteAll(m_repeatTimers);
m_repeatTimers.clear();
}
KeyboardInputRedirection::~KeyboardInputRedirection() = default;
void KeyboardInputRedirection::init()
{
Q_ASSERT(!m_inited);
m_inited = true;
// setup key repeat
m_keyRepeat.timer = new QTimer(this);
connect(m_keyRepeat.timer, &QTimer::timeout, this,
[this] {
if (waylandServer()->seat()->keyRepeatRate() != 0) {
m_keyRepeat.timer->setInterval(1000 / waylandServer()->seat()->keyRepeatRate());
}
// TODO: better time
processKey(m_keyRepeat.key, InputRedirection::KeyboardKeyAutoRepeat, m_keyRepeat.time);
}
);
connect(workspace(), &QObject::destroyed, this, [this] { m_inited = false; });
connect(waylandServer(), &QObject::destroyed, this, [this] { m_inited = false; });
connect(workspace(), &Workspace::clientActivated, this,
@ -615,26 +642,14 @@ void KeyboardInputRedirection::processKey(uint32_t key, InputRedirection::Keyboa
device);
if (state == InputRedirection::KeyboardKeyPressed) {
if (m_xkb->shouldKeyRepeat(key) && waylandServer()->seat()->keyRepeatDelay() != 0) {
QTimer *timer = new QTimer;
timer->setInterval(waylandServer()->seat()->keyRepeatDelay());
connect(timer, &QTimer::timeout, this,
[this, timer, time, key] {
const int delay = 1000 / waylandServer()->seat()->keyRepeatRate();
if (timer->interval() != delay) {
timer->setInterval(delay);
}
// TODO: better time
processKey(key, InputRedirection::KeyboardKeyAutoRepeat, time);
}
);
m_repeatTimers.insert(key, timer);
timer->start();
m_keyRepeat.timer->setInterval(waylandServer()->seat()->keyRepeatDelay());
m_keyRepeat.key = key;
m_keyRepeat.time = time;
m_keyRepeat.timer->start();
}
} else if (state == InputRedirection::KeyboardKeyReleased) {
auto it = m_repeatTimers.find(key);
if (it != m_repeatTimers.end()) {
delete it.value();
m_repeatTimers.erase(it);
if (key == m_keyRepeat.key) {
m_keyRepeat.timer->stop();
}
}

@ -140,8 +140,12 @@ private:
InputRedirection *m_input;
bool m_inited = false;
QScopedPointer<Xkb> m_xkb;
QHash<quint32, QTimer*> m_repeatTimers;
QMetaObject::Connection m_activeClientSurfaceChangedConnection;
struct {
quint32 key = 0;
quint32 time = 0;
QTimer *timer = nullptr;
} m_keyRepeat;
};
inline

@ -21,6 +21,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define KWIN_USERACTIONS_H
#include "ui_shortcutdialog.h"
#include <kwinglobals.h>
// Qt
#include <QDialog>
#include <QObject>
@ -52,7 +54,7 @@ class Client;
*
* @author Martin Gräßlin <mgraesslin@kde.org>
**/
class UserActionsMenu : public QObject
class KWIN_EXPORT UserActionsMenu : public QObject
{
Q_OBJECT
public:

Loading…
Cancel
Save