qt: parity batch 2 — mouse input (B8, B19, B25, B26)
Four fixes from PARITY.md tier 1 covering mouse-related actions: B8 + B26 — MOUSE_VISIBILITY no longer clobbers the cursor shape. GhosttySurface now tracks the requested shape (m_cursorShape) and visibility (m_mouseVisible) separately. setShape() sets the shape AND applies it if visible; setMouseVisible() flips visibility while preserving the shape. The action handler calls these instead of QWidget::setCursor directly. Previously, un-hiding the cursor reset it to ArrowCursor and lost any earlier MOUSE_SHAPE request from a running program. B19 — Mouse buttons 4-11 (back/forward/etc.) now delivered. Qt::ExtraButton1..ExtraButton8 map to GHOSTTY_MOUSE_FOUR..ELEVEN. Previously every side button fell to GHOSTTY_MOUSE_UNKNOWN and was silently dropped. macOS handles NSEvent buttonNumber 3-10; GTK handles GDK button 4-11 (apprt/gtk/class/surface.zig:3713). B25 — MOUSE_SHAPE was applied via setCursor with no preservation; now flows through setShape() which records the request. Combined with B26 above, the cursor shape requested by a program (e.g. vim's IBeam, hover-over-link Pointer) is preserved across hide/show cycles. B29 (XKB live layout) deferred to a follow-up — the right fix needs to listen for keyboard-layout changes from Qt or wl_keyboard, not read XKB_DEFAULT_LAYOUT once at process start. Co-Authored-By: claude-flow <ruv@ruv.net>pull/12846/head
parent
33b5dee468
commit
a48ff0fb89
|
|
@ -319,6 +319,17 @@ void GhosttySurface::flashBorder() {
|
|||
});
|
||||
}
|
||||
|
||||
void GhosttySurface::setShape(Qt::CursorShape shape) {
|
||||
m_cursorShape = shape;
|
||||
if (m_mouseVisible) setCursor(shape);
|
||||
}
|
||||
|
||||
void GhosttySurface::setMouseVisible(bool visible) {
|
||||
if (m_mouseVisible == visible) return;
|
||||
m_mouseVisible = visible;
|
||||
setCursor(visible ? m_cursorShape : Qt::BlankCursor);
|
||||
}
|
||||
|
||||
// A small translucent overlay label (key-sequence / resize display).
|
||||
static QLabel *makeOverlayLabel(QWidget *parent) {
|
||||
auto *label = new QLabel(parent);
|
||||
|
|
@ -712,6 +723,18 @@ void GhosttySurface::sendMouseButton(QMouseEvent *ev,
|
|||
case Qt::LeftButton: button = GHOSTTY_MOUSE_LEFT; break;
|
||||
case Qt::RightButton: button = GHOSTTY_MOUSE_RIGHT; break;
|
||||
case Qt::MiddleButton: button = GHOSTTY_MOUSE_MIDDLE; break;
|
||||
// Side / extra buttons (back, forward, etc.). macOS handles
|
||||
// NSEvent buttonNumber 3-10 and GTK handles GDK button 4-11;
|
||||
// Qt's ExtraButton1..ExtraButton8 cover the same hardware. The
|
||||
// libghostty C ABI defines FOUR..ELEVEN, so map by index.
|
||||
case Qt::ExtraButton1: button = GHOSTTY_MOUSE_FOUR; break;
|
||||
case Qt::ExtraButton2: button = GHOSTTY_MOUSE_FIVE; break;
|
||||
case Qt::ExtraButton3: button = GHOSTTY_MOUSE_SIX; break;
|
||||
case Qt::ExtraButton4: button = GHOSTTY_MOUSE_SEVEN; break;
|
||||
case Qt::ExtraButton5: button = GHOSTTY_MOUSE_EIGHT; break;
|
||||
case Qt::ExtraButton6: button = GHOSTTY_MOUSE_NINE; break;
|
||||
case Qt::ExtraButton7: button = GHOSTTY_MOUSE_TEN; break;
|
||||
case Qt::ExtraButton8: button = GHOSTTY_MOUSE_ELEVEN; break;
|
||||
default: button = GHOSTTY_MOUSE_UNKNOWN; break;
|
||||
}
|
||||
ghostty_surface_mouse_button(m_surface, state, button,
|
||||
|
|
|
|||
|
|
@ -103,6 +103,15 @@ public:
|
|||
void setBellTitle(bool marked) { m_bellTitle = marked; }
|
||||
bool bellTitle() const { return m_bellTitle; }
|
||||
|
||||
// Set the cursor shape from the libghostty MOUSE_SHAPE action.
|
||||
// Tracks the requested shape so MOUSE_VISIBILITY toggles can hide
|
||||
// and restore without forgetting it. macOS+GTK preserve shape
|
||||
// across visibility changes; the previous Qt code clobbered it
|
||||
// with Qt::ArrowCursor on un-hide.
|
||||
void setShape(Qt::CursorShape shape);
|
||||
// Hide or show the mouse cursor without changing its shape.
|
||||
void setMouseVisible(bool visible);
|
||||
|
||||
protected:
|
||||
bool event(QEvent *) override;
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
|
|
@ -197,6 +206,11 @@ private:
|
|||
bool m_notifyOnCommand = false; // one-shot: notify on next cmd finish
|
||||
bool m_bellFlash = false; // bell `border` flash in progress
|
||||
bool m_bellTitle = false; // unacknowledged bell `title` mark
|
||||
// Last requested cursor shape (from MOUSE_SHAPE) and visibility
|
||||
// (from MOUSE_VISIBILITY). Tracked separately so toggling
|
||||
// visibility doesn't reset the shape.
|
||||
Qt::CursorShape m_cursorShape = Qt::IBeamCursor;
|
||||
bool m_mouseVisible = true;
|
||||
// Tracks whether the prior inputMethodEvent reported active preedit.
|
||||
// Used to distinguish a real post-composition commit (forward to the
|
||||
// terminal) from the duplicate ASCII commit that Wayland's
|
||||
|
|
|
|||
|
|
@ -1511,7 +1511,7 @@ bool MainWindow::onAction(ghostty_app_t, ghostty_target_s target,
|
|||
const Qt::CursorShape shape =
|
||||
mouseShapeToCursor(action.action.mouse_shape);
|
||||
post(src, [srcp, shape]() {
|
||||
if (srcp) srcp->setCursor(shape);
|
||||
if (srcp) srcp->setShape(shape);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1570,10 +1570,12 @@ bool MainWindow::onAction(ghostty_app_t, ghostty_target_s target,
|
|||
|
||||
case GHOSTTY_ACTION_MOUSE_VISIBILITY: {
|
||||
if (!src) return false;
|
||||
const bool hidden =
|
||||
action.action.mouse_visibility == GHOSTTY_MOUSE_HIDDEN;
|
||||
post(src, [srcp, hidden]() {
|
||||
if (srcp) srcp->setCursor(hidden ? Qt::BlankCursor : Qt::ArrowCursor);
|
||||
const bool visible =
|
||||
action.action.mouse_visibility != GHOSTTY_MOUSE_HIDDEN;
|
||||
post(src, [srcp, visible]() {
|
||||
// setMouseVisible preserves the requested shape so toggling
|
||||
// doesn't reset to ArrowCursor.
|
||||
if (srcp) srcp->setMouseVisible(visible);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue