Implement support for window shortcuts for Wayland windows
Summary: Moves most of the implementation from Client to AbstractClient, so that it can be used for both Client and ShellClient. Only the X11 specific code is kept in Client. Not yet implemented is updating the window caption. Unfortunately the testing of this feature showed that setting a window shortcut is not working on Wayland at all (the Qt widget doesn't properly catch the shortcut). So this feature is currently only of erm theoretical use. Test Plan: Added new test case. No testing in real world as explained. Reviewers: #kwin, #plasma Subscribers: plasma-devel, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D6818
This commit is contained in:
parent
ddd957f0a6
commit
c29d6093ba
8 changed files with 81 additions and 41 deletions
|
@ -384,8 +384,10 @@ public:
|
|||
*/
|
||||
bool isSpecialWindow() const;
|
||||
void sendToScreen(int screen);
|
||||
virtual const QKeySequence &shortcut() const = 0;
|
||||
virtual void setShortcut(const QString &cut) = 0;
|
||||
const QKeySequence &shortcut() const {
|
||||
return _shortcut;
|
||||
}
|
||||
void setShortcut(const QString &cut);
|
||||
virtual bool performMouseCommand(Options::MouseCommand, const QPoint &globalPos);
|
||||
void setOnAllDesktops(bool set);
|
||||
void setDesktop(int);
|
||||
|
@ -991,6 +993,8 @@ protected:
|
|||
|
||||
void setUnresponsive(bool unresponsive);
|
||||
|
||||
virtual void setShortcutInternal();
|
||||
|
||||
private:
|
||||
void handlePaletteChange();
|
||||
QSharedPointer<TabBox::TabBoxClientImpl> m_tabBoxClient;
|
||||
|
@ -1065,6 +1069,8 @@ private:
|
|||
|
||||
bool m_unresponsive = false;
|
||||
|
||||
QKeySequence _shortcut;
|
||||
|
||||
static bool s_haveResizeEffect;
|
||||
};
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ private Q_SLOTS:
|
|||
void testUserActionsMenu();
|
||||
void testMetaShiftW();
|
||||
void testX11ClientShortcut();
|
||||
void testWaylandClientShortcut();
|
||||
};
|
||||
|
||||
void GlobalShortcutsTest::initTestCase()
|
||||
|
@ -277,5 +278,43 @@ void GlobalShortcutsTest::testX11ClientShortcut()
|
|||
QVERIFY(windowClosedSpy.wait());
|
||||
}
|
||||
|
||||
void GlobalShortcutsTest::testWaylandClientShortcut()
|
||||
{
|
||||
QScopedPointer<Surface> surface(Test::createSurface());
|
||||
QScopedPointer<ShellSurface> shellSurface(Test::createShellSurface(surface.data()));
|
||||
auto client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
||||
|
||||
QCOMPARE(workspace()->activeClient(), client);
|
||||
QVERIFY(client->isActive());
|
||||
QCOMPARE(client->shortcut(), QKeySequence());
|
||||
const QKeySequence seq(Qt::META + Qt::SHIFT + Qt::Key_Y);
|
||||
QVERIFY(workspace()->shortcutAvailable(seq));
|
||||
client->setShortcut(seq.toString());
|
||||
QCOMPARE(client->shortcut(), seq);
|
||||
QVERIFY(!workspace()->shortcutAvailable(seq));
|
||||
QEXPECT_FAIL("", "Caption adjustment not yet implemented", Continue);
|
||||
QCOMPARE(client->caption(), QStringLiteral(" {Meta+Shift+Y}"));
|
||||
|
||||
workspace()->activateClient(nullptr);
|
||||
QVERIFY(!workspace()->activeClient());
|
||||
QVERIFY(!client->isActive());
|
||||
|
||||
// now let's trigger the shortcut
|
||||
quint32 timestamp = 0;
|
||||
kwinApp()->platform()->keyboardKeyPressed(KEY_LEFTMETA, timestamp++);
|
||||
kwinApp()->platform()->keyboardKeyPressed(KEY_LEFTSHIFT, timestamp++);
|
||||
kwinApp()->platform()->keyboardKeyPressed(KEY_Y, timestamp++);
|
||||
QTRY_COMPARE(workspace()->activeClient(), client);
|
||||
kwinApp()->platform()->keyboardKeyReleased(KEY_Y, timestamp++);
|
||||
kwinApp()->platform()->keyboardKeyReleased(KEY_LEFTSHIFT, timestamp++);
|
||||
kwinApp()->platform()->keyboardKeyReleased(KEY_LEFTMETA, timestamp++);
|
||||
|
||||
shellSurface.reset();
|
||||
surface.reset();
|
||||
QVERIFY(Test::waitForWindowDestroyed(client));
|
||||
QVERIFY(workspace()->shortcutAvailable(seq));
|
||||
}
|
||||
|
||||
|
||||
WAYLANDTEST_MAIN(GlobalShortcutsTest)
|
||||
#include "globalshortcuts_test.moc"
|
||||
|
|
10
client.h
10
client.h
|
@ -200,8 +200,6 @@ public:
|
|||
QSize sizeForClientSize(const QSize&, Sizemode mode = SizemodeAny, bool noframe = false) const override;
|
||||
|
||||
bool providesContextHelp() const override;
|
||||
const QKeySequence &shortcut() const override;
|
||||
void setShortcut(const QString& cut) override;
|
||||
|
||||
Options::WindowOperation mouseButtonToWindowOperation(Qt::MouseButtons button);
|
||||
bool performMouseCommand(Options::MouseCommand, const QPoint& globalPos) override;
|
||||
|
@ -451,7 +449,7 @@ private:
|
|||
void setCaption(const QString& s, bool force = false);
|
||||
bool hasTransientInternal(const Client* c, bool indirect, ConstClientList& set) const;
|
||||
void finishWindowRules();
|
||||
void setShortcutInternal(const QKeySequence &cut = QKeySequence());
|
||||
void setShortcutInternal() override;
|
||||
|
||||
void configureRequest(int value_mask, int rx, int ry, int rw, int rh, int gravity, bool from_tool);
|
||||
NETExtendedStrut strut() const;
|
||||
|
@ -579,7 +577,6 @@ private:
|
|||
bool isPending;
|
||||
} syncRequest;
|
||||
static bool check_active_modal; ///< \see Client::checkActiveModal()
|
||||
QKeySequence _shortcut;
|
||||
int sm_stacking_order;
|
||||
friend struct ResetupRulesProcedure;
|
||||
|
||||
|
@ -738,11 +735,6 @@ inline xcb_window_t Client::moveResizeGrabWindow() const
|
|||
return m_moveResizeGrabWindow;
|
||||
}
|
||||
|
||||
inline const QKeySequence &Client::shortcut() const
|
||||
{
|
||||
return _shortcut;
|
||||
}
|
||||
|
||||
inline void Client::removeRule(Rules* rule)
|
||||
{
|
||||
client_rules.remove(rule);
|
||||
|
|
|
@ -820,17 +820,6 @@ void ShellClient::setOnAllActivities(bool set)
|
|||
Q_UNUSED(set)
|
||||
}
|
||||
|
||||
void ShellClient::setShortcut(const QString &cut)
|
||||
{
|
||||
Q_UNUSED(cut)
|
||||
}
|
||||
|
||||
const QKeySequence &ShellClient::shortcut() const
|
||||
{
|
||||
static QKeySequence seq;
|
||||
return seq;
|
||||
}
|
||||
|
||||
void ShellClient::takeFocus()
|
||||
{
|
||||
if (rules()->checkAcceptFocus(wantsInput())) {
|
||||
|
|
|
@ -89,8 +89,6 @@ public:
|
|||
void setNoBorder(bool set) override;
|
||||
void updateDecoration(bool check_workspace_pos, bool force = false) override;
|
||||
void setOnAllActivities(bool set) override;
|
||||
void setShortcut(const QString &cut) override;
|
||||
const QKeySequence &shortcut() const override;
|
||||
void takeFocus() override;
|
||||
void updateWindowRules(Rules::Types selection) override;
|
||||
bool userCanSetFullScreen() const override;
|
||||
|
|
|
@ -1044,7 +1044,7 @@ void Workspace::setupWindowShortcutDone(bool ok)
|
|||
active_client->takeFocus();
|
||||
}
|
||||
|
||||
void Workspace::clientShortcutUpdated(Client* c)
|
||||
void Workspace::clientShortcutUpdated(AbstractClient* c)
|
||||
{
|
||||
QString key = QStringLiteral("_k_session:%1").arg(c->window());
|
||||
QAction* action = findChild<QAction*>(key);
|
||||
|
@ -1794,11 +1794,19 @@ void Workspace::slotInvertScreen()
|
|||
|
||||
#undef USABLE_ACTIVE_CLIENT
|
||||
|
||||
void Client::setShortcut(const QString& _cut)
|
||||
void AbstractClient::setShortcut(const QString& _cut)
|
||||
{
|
||||
QString cut = rules()->checkShortcut(_cut);
|
||||
if (cut.isEmpty())
|
||||
return setShortcutInternal();
|
||||
auto updateShortcut = [this](const QKeySequence &cut = QKeySequence()) {
|
||||
if (_shortcut == cut)
|
||||
return;
|
||||
_shortcut = cut;
|
||||
setShortcutInternal();
|
||||
};
|
||||
if (cut.isEmpty()) {
|
||||
updateShortcut();
|
||||
return;
|
||||
}
|
||||
if (cut == shortcut().toString()) {
|
||||
return; // no change
|
||||
}
|
||||
|
@ -1807,9 +1815,9 @@ void Client::setShortcut(const QString& _cut)
|
|||
// E.g. Alt+Ctrl+(ABCDEF);Meta+X,Meta+(ABCDEF)
|
||||
if (!cut.contains(QLatin1Char('(')) && !cut.contains(QLatin1Char(')')) && !cut.contains(QLatin1String(" - "))) {
|
||||
if (workspace()->shortcutAvailable(cut, this))
|
||||
setShortcutInternal(QKeySequence(cut));
|
||||
updateShortcut(QKeySequence(cut));
|
||||
else
|
||||
setShortcutInternal();
|
||||
updateShortcut();
|
||||
return;
|
||||
}
|
||||
QList< QKeySequence > keys;
|
||||
|
@ -1846,18 +1854,20 @@ void Client::setShortcut(const QString& _cut)
|
|||
it != keys.constEnd();
|
||||
++it) {
|
||||
if (workspace()->shortcutAvailable(*it, this)) {
|
||||
setShortcutInternal(*it);
|
||||
updateShortcut(*it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
setShortcutInternal();
|
||||
updateShortcut();
|
||||
}
|
||||
|
||||
void Client::setShortcutInternal(const QKeySequence &cut)
|
||||
void AbstractClient::setShortcutInternal()
|
||||
{
|
||||
workspace()->clientShortcutUpdated(this);
|
||||
}
|
||||
|
||||
void Client::setShortcutInternal()
|
||||
{
|
||||
if (_shortcut == cut)
|
||||
return;
|
||||
_shortcut = cut;
|
||||
updateCaption();
|
||||
#if 0
|
||||
workspace()->clientShortcutUpdated(this);
|
||||
|
@ -1874,7 +1884,7 @@ void Client::delayedSetShortcut()
|
|||
workspace()->clientShortcutUpdated(this);
|
||||
}
|
||||
|
||||
bool Workspace::shortcutAvailable(const QKeySequence &cut, Client* ignore) const
|
||||
bool Workspace::shortcutAvailable(const QKeySequence &cut, AbstractClient* ignore) const
|
||||
{
|
||||
if (ignore && cut == ignore->shortcut())
|
||||
return true;
|
||||
|
@ -1882,8 +1892,8 @@ bool Workspace::shortcutAvailable(const QKeySequence &cut, Client* ignore) const
|
|||
if (!KGlobalAccel::getGlobalShortcutsByKey(cut).isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (ClientList::ConstIterator it = clients.constBegin();
|
||||
it != clients.constEnd();
|
||||
for (auto it = m_allClients.constBegin();
|
||||
it != m_allClients.constEnd();
|
||||
++it) {
|
||||
if ((*it) != ignore && (*it)->shortcut() == cut)
|
||||
return false;
|
||||
|
|
|
@ -434,6 +434,12 @@ void Workspace::init()
|
|||
if (c == last_active_client) {
|
||||
last_active_client = nullptr;
|
||||
}
|
||||
if (client_keys_client == c) {
|
||||
setupWindowShortcutDone(false);
|
||||
}
|
||||
if (!c->shortcut().isEmpty()) {
|
||||
c->setShortcut(QString()); // Remove from client_keys
|
||||
}
|
||||
clientHidden(c);
|
||||
emit clientRemoved(c);
|
||||
markXStackingOrderAsDirty();
|
||||
|
|
|
@ -326,8 +326,8 @@ public:
|
|||
|
||||
void focusToNull(); // SELI TODO: Public?
|
||||
|
||||
void clientShortcutUpdated(Client* c);
|
||||
bool shortcutAvailable(const QKeySequence &cut, Client* ignore = NULL) const;
|
||||
void clientShortcutUpdated(AbstractClient* c);
|
||||
bool shortcutAvailable(const QKeySequence &cut, AbstractClient* ignore = NULL) const;
|
||||
bool globalShortcutsDisabled() const;
|
||||
void disableGlobalShortcutsForClient(bool disable);
|
||||
|
||||
|
|
Loading…
Reference in a new issue