From ea7d84868d139e4ee94afad8bdd10bc252bd198b Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Thu, 8 Oct 2026 11:58:02 +0200 Subject: [PATCH] Radial: warp the mouse to the pane after a focus-change split action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a radial slice fires a go_*_split_view action (Focus Left/Right/Up/ Down/Next/Prev), warp the OS pointer onto the center of the newly active view so the mouse follows the keyboard focus. Deferred via a 0ms timer so Kate finishes activating the target view first. Scoped to the six pane- focus actions only — other radial activations and ordinary view changes (clicks, file opens) do not move the pointer. --- src/plugin/ollieplugin.cpp | 32 ++++++++++++++++++++++++++++++++ src/plugin/ollieplugin.h | 4 ++++ 2 files changed, 36 insertions(+) diff --git a/src/plugin/ollieplugin.cpp b/src/plugin/ollieplugin.cpp index 2d6a3d8..b54c331 100644 --- a/src/plugin/ollieplugin.cpp +++ b/src/plugin/ollieplugin.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include #include #include +#include #include #include @@ -43,6 +45,19 @@ namespace katecustom namespace { +// True for the Kate actions that move keyboard focus to another split pane. +// After one of these fires we warp the mouse pointer onto the new pane so the +// cursor follows the focus (mouse-first UX). +bool isPaneFocusAction(const QString &id) +{ + return id == QLatin1String("go_left_split_view") + || id == QLatin1String("go_right_split_view") + || id == QLatin1String("go_upward_split_view") + || id == QLatin1String("go_downward_split_view") + || id == QLatin1String("go_next_split_view") + || id == QLatin1String("go_prev_split_view"); +} + // Bracket pairs understood by the double-click selection feature. QChar matchingBracket(QChar c, bool &isOpener) { @@ -1136,9 +1151,26 @@ void OllieView::onRadialActivated(const QString &actionId) } if (QAction *a = findActionByName(actionId)) { a->trigger(); + // If this moved focus to another split pane, warp the pointer onto that + // pane so the mouse follows the focus. Deferred to the next event-loop + // turn so Kate has finished activating the target view first. + if (isPaneFocusAction(actionId)) { + QTimer::singleShot(0, this, [this]() { warpCursorToActiveView(); }); + } } } +void OllieView::warpCursorToActiveView() +{ + KTextEditor::View *view = m_mainWindow->activeView(); + if (!view) { + return; + } + // KTextEditor::View is a QWidget; center the pointer in its editing area. + const QPoint center = view->mapToGlobal(view->rect().center()); + QCursor::setPos(center); +} + // --------------------------------------------------------------------------- // Acme-style line-editing keys // diff --git a/src/plugin/ollieplugin.h b/src/plugin/ollieplugin.h index 9076ea7..6e65d90 100644 --- a/src/plugin/ollieplugin.h +++ b/src/plugin/ollieplugin.h @@ -89,6 +89,10 @@ private: // Size and place a palette: it spans the active window's width (minus a // small margin), anchored near the top. void positionPalette(PaletteWidget *palette); + + // Move the OS pointer onto the center of the active view — used after a + // radial pane-focus action so the mouse follows the keyboard focus. + void warpCursorToActiveView(); // One harvested, runnable action with the provenance needed to build a // unique id and to disambiguate labels shared by several commands. struct ActionEntry {