Skip to content

feat: GTK tab/editor context menus use engine-drawn rendering - #137

Merged
JDonaghy merged 11 commits into
developfrom
issue-135-gtk-context-menu
Apr 18, 2026
Merged

feat: GTK tab/editor context menus use engine-drawn rendering#137
JDonaghy merged 11 commits into
developfrom
issue-135-gtk-context-menu

Conversation

@JDonaghy

Copy link
Copy Markdown
Owner

Summary

  • Tab-bar and editor right-click context menus in GTK now render from engine data via draw_context_menu_popup() instead of native PopoverMenu widgets
  • Click handling uses shared resolve_context_menu_click() from Hit regions for context menus + dialogs #43
  • Keyboard navigation: j/k to move, Enter to confirm, Escape to dismiss
  • Explorer right-click still uses PopoverMenu (tied to GTK TreeView)

Before/After

Before: Native GTK PopoverMenu with OS-styled items
After: Engine-drawn popup matching TUI/Win-GUI visual style — consistent across all backends

Test plan

  • cargo clippy -- -D warnings — clean
  • Full suite: 1939 passed, 0 failed

Smoke test (GTK)

  1. Right-click on a tab → should show engine-drawn context menu (not native GTK popover)
  2. Click a menu item → should execute action (close tab, close others, etc.)
  3. Click outside → should dismiss
  4. Press j/k to navigate, Enter to confirm, Escape to dismiss
  5. Right-click in editor → should show editor context menu (cut/copy/paste etc.)

Partial #135

🤖 Generated with Claude Code

JDonaghy and others added 11 commits April 17, 2026 20:58
Adds a Cairo-based context menu renderer in gtk/draw.rs that draws
from render::ContextMenuPanel — the same data TUI and Win-GUI use.
Wired into the draw loop but currently no-op because GTK still
closes the engine context menu before drawing (PopoverMenu is still
active). The full migration (removing PopoverMenu, keeping engine
context menu alive, adding click handling) is a follow-up.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Migrates GTK tab-bar and editor right-click context menus from native
PopoverMenu widgets to engine-driven rendering via draw_context_menu_popup().
Tab and editor right-clicks now call engine.open_*_context_menu() with
char-cell coordinates, keeping the engine context menu alive for rendering.

Changes:
- Tab right-click: engine.open_tab_context_menu() instead of PopoverMenu
- Editor right-click: engine.open_editor_context_menu() instead of PopoverMenu
- Left-click handling: resolve_context_menu_click() dismisses or selects
- Keyboard handling: Escape dismisses, j/k navigate, Enter confirms
- draw_context_menu_popup() renders from ContextMenuPanel (same as TUI/Win-GUI)

Explorer right-click still uses PopoverMenu (tied to GTK TreeView widget).
Old handler methods kept with #[allow(dead_code)] for reference.

Partial #135

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds EventControllerMotion on the drawing area that updates
context_menu.selected as the mouse moves over items, triggering
a redraw for highlight feedback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The motion callback fires during GTK event loop iterations where the
engine RefCell may already be borrowed by the draw function. Using
try_borrow_mut() skips the hover update gracefully instead of panicking.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Motion callback uses try_borrow()/try_borrow_mut() with separate
  scopes to avoid RefCell panics in GTK's extern "C" callback
- No unwrap() calls that could panic across FFI boundary
- Updated CLAUDE.md: don't push until user approves smoke tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove the separate EventControllerMotion that was causing RefCell
panics across GTK's extern "C" boundary. Instead, add hover logic
to the existing mouse_pos_cell motion handler — uses try_borrow_mut
and computes the new selection index from an immutable borrow before
mutating, avoiding any unwrap() calls in the FFI callback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…backs

Mouse hover highlighting in engine-drawn context menus causes RefCell
panics across GTK's extern "C" FFI boundary. Removed all hover logic.
Context menus still work via click and keyboard (j/k/Enter/Escape).
Hover can be revisited when the drawing architecture avoids holding
engine borrows during GTK signal dispatch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of mutating engine state in a motion callback (which causes
RefCell panics across GTK's extern C boundary), compute the hovered
item inside draw_context_menu_popup() from the existing mouse_pos_cell.
Motion callback just triggers queue_draw() when a context menu is open
(using try_borrow to safely check).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- resolve_context_menu_click: use saturating_sub to prevent overflow
  when click_row == py (clicking on the top border)
- draw_context_menu_popup: only highlight when mouse is directly over
  an item; when mouse is on separator/border inside popup, no highlight;
  when mouse is outside popup, fall back to keyboard selection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Motion callback updates engine.context_menu.selected via try_borrow_mut
  so the selection persists when mouse leaves the popup
- Draw function uses hover_idx (from mouse_pos) with fallback to
  cm.selected_idx — keeps last-hovered item highlighted when mouse exits
- Disabled items already use theme.line_number_fg (dim grey) vs
  theme.fuzzy_fg (normal text) for visual distinction

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use fuzzy_fg.darken(0.5) for disabled items instead of line_number_fg
which was too similar to the normal text color on some themes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@JDonaghy
JDonaghy merged commit 2c848b7 into develop Apr 18, 2026
0 of 4 checks passed
JDonaghy added a commit that referenced this pull request May 16, 2026
…#395)

The engine-drawn context-menu path (paint at draw.rs::draw_context_menu_popup,
click dispatch + hover via cached ContextMenuLayout at gtk/mod.rs:6022,
keyboard via engine::handle_context_menu_key) was fully wired in earlier
work (#137, #210/#425) but the editor "..." action menu kept building a
native gtk4::PopoverMenu on top. Two right-click handlers
(handle_tab_right_click, handle_editor_right_click) had already been
replaced by Msg::TabRightClick (mod.rs:4014) / Msg::EditorRightClick
(mod.rs:4042) but their bodies were left behind with #[allow(dead_code)].

- click.rs::handle_mouse_click derives (col, row) from the click's
  pixel coords when opening the editor action menu, so the engine's
  ContextMenuState anchor lands under the "..." button instead of (0, 0).
- gtk/mod.rs drops the show_action_menu_popover call branch; the
  engine-drawn renderer + click dispatch take over from there.
- Deletes 3 unused functions (~497 lines): show_action_menu_popover,
  handle_tab_right_click, handle_editor_right_click.

Explorer context menu (show_explorer_context_menu) stays on native
PopoverMenu in this PR — engine-drawn ctx menu paints on the editor
DA, but explorer right-clicks happen on the explorer DA (separate
GTK widget, independent coord system). Cross-DA handling tracked in
#426.

Refs #395.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
JDonaghy added a commit that referenced this pull request May 16, 2026
…#395)

The engine-drawn context-menu path (paint at draw.rs::draw_context_menu_popup,
click dispatch + hover via cached ContextMenuLayout at gtk/mod.rs:6022,
keyboard via engine::handle_context_menu_key) was fully wired in earlier
work (#137, #210/#425) but the editor "..." action menu kept building a
native gtk4::PopoverMenu on top. Two right-click handlers
(handle_tab_right_click, handle_editor_right_click) had already been
replaced by Msg::TabRightClick (mod.rs:4014) / Msg::EditorRightClick
(mod.rs:4042) but their bodies were left behind with #[allow(dead_code)].

- click.rs::handle_mouse_click derives (col, row) from the click's
  pixel coords when opening the editor action menu, so the engine's
  ContextMenuState anchor lands under the "..." button instead of (0, 0).
- gtk/mod.rs drops the show_action_menu_popover call branch; the
  engine-drawn renderer + click dispatch take over from there.
- Deletes 3 unused functions (~497 lines): show_action_menu_popover,
  handle_tab_right_click, handle_editor_right_click.

Explorer context menu (show_explorer_context_menu) stays on native
PopoverMenu in this PR — engine-drawn ctx menu paints on the editor
DA, but explorer right-clicks happen on the explorer DA (separate
GTK widget, independent coord system). Cross-DA handling tracked in

Refs #395.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant