Allow corner-tiling by quickly combining edge tiling shortcuts
Currently the only way for a uuser to invoke corner-tiling is to manually set shortcuts for them. This patch adds another option: invoke the existing shortcuts for edge tiling in a combined manner in quick succession. For example, hitting Meta+Left and then Meta+Up within a one-second period will tile the active window into the top left corner. In practice you hold down the Meta key and then press Left then Up (or Up and then Left), and I think it feels very natural. Linux Mint's window manager has this feature and I always missed it when I left Mint for the KDE world. Autotests for existing tiling shortcuts are adjusted to not break, and additional tests for the new tiling options are added.
This commit is contained in:
parent
e9c68f36bd
commit
87578bfc15
4 changed files with 60 additions and 24 deletions
|
@ -709,21 +709,25 @@ void QuickTilingTest::testX11QuickTilingAfterVertMaximize()
|
|||
|
||||
void QuickTilingTest::testShortcut_data()
|
||||
{
|
||||
QTest::addColumn<QString>("shortcut");
|
||||
QTest::addColumn<QStringList>("shortcutList");
|
||||
QTest::addColumn<QuickTileMode>("expectedMode");
|
||||
QTest::addColumn<QRect>("expectedGeometry");
|
||||
|
||||
#define FLAG(name) QuickTileMode(QuickTileFlag::name)
|
||||
QTest::newRow("top") << QStringLiteral("Window Quick Tile Top") << FLAG(Top) << QRect(0, 0, 1280, 512);
|
||||
QTest::newRow("left") << QStringLiteral("Window Quick Tile Left") << FLAG(Left) << QRect(0, 0, 640, 1024);
|
||||
QTest::newRow("bottom") << QStringLiteral("Window Quick Tile Bottom") << FLAG(Bottom) << QRect(0, 512, 1280, 512);
|
||||
QTest::newRow("right") << QStringLiteral("Window Quick Tile Right") << FLAG(Right) << QRect(640, 0, 640, 1024);
|
||||
|
||||
QTest::newRow("top right") << QStringLiteral("Window Quick Tile Top Right") << (FLAG(Top) | FLAG(Right)) << QRect(640, 0, 640, 512);
|
||||
QTest::newRow("top left") << QStringLiteral("Window Quick Tile Top Left") << (FLAG(Top) | FLAG(Left)) << QRect(0, 0, 640, 512);
|
||||
QTest::newRow("bottom right") << QStringLiteral("Window Quick Tile Bottom Right") << (FLAG(Bottom) | FLAG(Right)) << QRect(640, 512, 640, 512);
|
||||
QTest::newRow("bottom left") << QStringLiteral("Window Quick Tile Bottom Left") << (FLAG(Bottom) | FLAG(Left)) << QRect(0, 512, 640, 512);
|
||||
QTest::newRow("top") << QStringList{QStringLiteral("Window Quick Tile Top")} << FLAG(Top) << QRect(0, 0, 1280, 512);
|
||||
QTest::newRow("bottom") << QStringList{QStringLiteral("Window Quick Tile Bottom")} << FLAG(Bottom) << QRect(0, 512, 1280, 512);
|
||||
QTest::newRow("top right") << QStringList{QStringLiteral("Window Quick Tile Top Right")} << (FLAG(Top) | FLAG(Right)) << QRect(640, 0, 640, 512);
|
||||
QTest::newRow("top left") << QStringList{QStringLiteral("Window Quick Tile Top Left")} << (FLAG(Top) | FLAG(Left)) << QRect(0, 0, 640, 512);
|
||||
QTest::newRow("bottom right") << QStringList{QStringLiteral("Window Quick Tile Bottom Right")} << (FLAG(Bottom) | FLAG(Right)) << QRect(640, 512, 640, 512);
|
||||
QTest::newRow("bottom left") << QStringList{QStringLiteral("Window Quick Tile Bottom Left")} << (FLAG(Bottom) | FLAG(Left)) << QRect(0, 512, 640, 512);
|
||||
QTest::newRow("left") << QStringList{QStringLiteral("Window Quick Tile Left")} << FLAG(Left) << QRect(0, 0, 640, 1024);
|
||||
QTest::newRow("right") << QStringList{QStringLiteral("Window Quick Tile Right")} << FLAG(Right) << QRect(640, 0, 640, 1024);
|
||||
|
||||
// Test combined actions for corner tiling
|
||||
QTest::newRow("top left combined") << QStringList{QStringLiteral("Window Quick Tile Left"), QStringLiteral("Window Quick Tile Top")} << (FLAG(Top) | FLAG(Left)) << QRect(0, 0, 640, 512);
|
||||
QTest::newRow("top right combined") << QStringList{QStringLiteral("Window Quick Tile Right"), QStringLiteral("Window Quick Tile Top")} << (FLAG(Top) | FLAG(Right)) << QRect(640, 0, 640, 512);
|
||||
QTest::newRow("bottom left combined") << QStringList{QStringLiteral("Window Quick Tile Left"), QStringLiteral("Window Quick Tile Bottom")} << (FLAG(Bottom) | FLAG(Left)) << QRect(0, 512, 640, 512);
|
||||
QTest::newRow("bottom right combined") << QStringList{QStringLiteral("Window Quick Tile Right"), QStringLiteral("Window Quick Tile Bottom")} << (FLAG(Bottom) | FLAG(Right)) << QRect(640, 512, 640, 512);
|
||||
#undef FLAG
|
||||
}
|
||||
|
||||
|
@ -749,9 +753,16 @@ void QuickTilingTest::testShortcut()
|
|||
QVERIFY(configureRequestedSpy.wait());
|
||||
QCOMPARE(configureRequestedSpy.count(), 1);
|
||||
|
||||
QFETCH(QString, shortcut);
|
||||
QFETCH(QStringList, shortcutList);
|
||||
QFETCH(QRect, expectedGeometry);
|
||||
|
||||
const int numberOfQuickTileActions = shortcutList.count();
|
||||
|
||||
if (numberOfQuickTileActions > 1) {
|
||||
QTest::qWait(1001);
|
||||
}
|
||||
|
||||
for (QString shortcut : shortcutList) {
|
||||
// invoke global shortcut through dbus
|
||||
auto msg = QDBusMessage::createMethodCall(
|
||||
QStringLiteral("org.kde.kglobalaccel"),
|
||||
|
@ -760,11 +771,12 @@ void QuickTilingTest::testShortcut()
|
|||
QStringLiteral("invokeShortcut"));
|
||||
msg.setArguments(QList<QVariant>{shortcut});
|
||||
QDBusConnection::sessionBus().asyncCall(msg);
|
||||
}
|
||||
|
||||
QSignalSpy quickTileChangedSpy(c, &AbstractClient::quickTileModeChanged);
|
||||
QVERIFY(quickTileChangedSpy.isValid());
|
||||
QVERIFY(quickTileChangedSpy.wait());
|
||||
QCOMPARE(quickTileChangedSpy.count(), 1);
|
||||
QCOMPARE(quickTileChangedSpy.count(), numberOfQuickTileActions);
|
||||
// at this point the geometry did not yet change
|
||||
QCOMPARE(c->frameGeometry(), QRect(0, 0, 100, 50));
|
||||
// but quick tile mode already changed
|
||||
|
@ -795,15 +807,13 @@ void QuickTilingTest::testScript_data()
|
|||
|
||||
#define FLAG(name) QuickTileMode(QuickTileFlag::name)
|
||||
QTest::newRow("top") << QStringLiteral("Top") << FLAG(Top) << QRect(0, 0, 1280, 512);
|
||||
QTest::newRow("left") << QStringLiteral("Left") << FLAG(Left) << QRect(0, 0, 640, 1024);
|
||||
QTest::newRow("bottom") << QStringLiteral("Bottom") << FLAG(Bottom) << QRect(0, 512, 1280, 512);
|
||||
QTest::newRow("right") << QStringLiteral("Right") << FLAG(Right) << QRect(640, 0, 640, 1024);
|
||||
|
||||
QTest::newRow("top right") << QStringLiteral("TopRight") << (FLAG(Top) | FLAG(Right)) << QRect(640, 0, 640, 512);
|
||||
QTest::newRow("top left") << QStringLiteral("TopLeft") << (FLAG(Top) | FLAG(Left)) << QRect(0, 0, 640, 512);
|
||||
QTest::newRow("bottom right") << QStringLiteral("BottomRight") << (FLAG(Bottom) | FLAG(Right)) << QRect(640, 512, 640, 512);
|
||||
QTest::newRow("bottom left") << QStringLiteral("BottomLeft") << (FLAG(Bottom) | FLAG(Left)) << QRect(0, 512, 640, 512);
|
||||
|
||||
QTest::newRow("left") << QStringLiteral("Left") << FLAG(Left) << QRect(0, 0, 640, 1024);
|
||||
QTest::newRow("right") << QStringLiteral("Right") << FLAG(Right) << QRect(640, 0, 640, 1024);
|
||||
#undef FLAG
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
#include <QRect>
|
||||
#include <QTextStream>
|
||||
#include <QTimer>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -837,6 +838,24 @@ void Workspace::quickTileWindow(QuickTileMode mode)
|
|||
return;
|
||||
}
|
||||
|
||||
// If the user invokes two of these commands in a one second period, try to
|
||||
// combine them together to enable easy and intuitive corner tiling
|
||||
#define FLAG(name) QuickTileMode(QuickTileFlag::name)
|
||||
if (!m_quickTileCombineTimer->isActive()) {
|
||||
m_quickTileCombineTimer->start(1000);
|
||||
m_lastTilingMode = mode;
|
||||
} else {
|
||||
if (
|
||||
( (m_lastTilingMode == FLAG(Left) || m_lastTilingMode == FLAG(Right)) && (mode == FLAG(Top) || mode == FLAG(Bottom)) )
|
||||
||
|
||||
( (m_lastTilingMode == FLAG(Top) || m_lastTilingMode == FLAG(Bottom)) && (mode == FLAG(Left) || mode == FLAG(Right)) )
|
||||
#undef FLAG
|
||||
) {
|
||||
mode |= m_lastTilingMode;
|
||||
}
|
||||
m_quickTileCombineTimer->stop();
|
||||
}
|
||||
|
||||
active_client->setQuickTileMode(mode, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -129,6 +129,8 @@ Workspace::Workspace()
|
|||
, set_active_client_recursion(0)
|
||||
, block_stacking_updates(0)
|
||||
, m_sessionManager(new SessionManager(this))
|
||||
, m_quickTileCombineTimer(nullptr)
|
||||
, m_lastTilingMode(0)
|
||||
{
|
||||
// If KWin was already running it saved its configuration after loosing the selection -> Reread
|
||||
QFuture<void> reparseConfigFuture = QtConcurrent::run(options, &Options::reparseConfiguration);
|
||||
|
@ -155,6 +157,9 @@ Workspace::Workspace()
|
|||
|
||||
delayFocusTimer = nullptr;
|
||||
|
||||
m_quickTileCombineTimer = new QTimer(this);
|
||||
m_quickTileCombineTimer->setSingleShot(true);
|
||||
|
||||
RuleBook::create(this)->load();
|
||||
|
||||
kwinApp()->createScreens();
|
||||
|
|
|
@ -250,6 +250,8 @@ public:
|
|||
|
||||
private:
|
||||
Compositor *m_compositor;
|
||||
QTimer *m_quickTileCombineTimer;
|
||||
QuickTileMode m_lastTilingMode;
|
||||
|
||||
//-------------------------------------------------
|
||||
// Unsorted
|
||||
|
|
Loading…
Reference in a new issue