From 6113ff7448af331239d967bdacedaa506bc170a6 Mon Sep 17 00:00:00 2001 From: carsten Date: Wed, 21 Jan 2026 14:44:06 +0100 Subject: [PATCH 1/2] menu@cinnamon.org: Add right-click context menu to search entry Enable copy/paste via right-click in the start menu search field by using CinnamonEntry.addContextMenu(). Previously only Ctrl+V worked for pasting. Fixes #13416 --- files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js index e2d290d0d9..03bfc8d54c 100644 --- a/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js @@ -26,6 +26,7 @@ const Pango = imports.gi.Pango; const SearchProviderManager = imports.ui.searchProviderManager; const SignalManager = imports.misc.signalManager; const Params = imports.misc.params; +const CinnamonEntry = imports.ui.cinnamonEntry; const INITIAL_BUTTON_LOAD = 30; @@ -2578,6 +2579,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { accessible_role: Atk.Role.ENTRY, }); this.searchEntry.add_accessible_state(Atk.StateType.EDITABLE); + CinnamonEntry.addContextMenu(this.searchEntry); this.searchEntry.set_secondary_icon(this._searchInactiveIcon); this.searchActive = false; From 868cb03b3311cf5c9cfc2d0bed796a20c6f3bead Mon Sep 17 00:00:00 2001 From: carsten Date: Fri, 23 Jan 2026 09:10:05 +0100 Subject: [PATCH 2/2] Fix right-click context menu in search entry Fixes #13416 The menu search field didn't support right-click copy/paste properly. Users could only paste with Ctrl+V keyboard shortcut. Changes: - Add CinnamonEntry.addContextMenu() to enable right-click context menu - Prevent context menu from grabbing modal focus (shouldGrab = false) - Close context menu when main menu closes - Extend _eventIsOnActiveMenu to treat context menu as part of active menu - Add manual hover effect using mouse position polling and CSS pseudo-class (required because MenuManager blocks normal hover events) --- .../applets/menu@cinnamon.org/applet.js | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js index 03bfc8d54c..9141c40316 100644 --- a/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js @@ -2580,6 +2580,55 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { }); this.searchEntry.add_accessible_state(Atk.StateType.EDITABLE); CinnamonEntry.addContextMenu(this.searchEntry); + this.searchEntry._menuManager.shouldGrab = false; + + // Close the search entry context menu when main menu closes + this.menu.connect('open-state-changed', (menu, open) => { + if (!open && this.searchEntry._menu.isOpen) { + this.searchEntry._menu.close(); + } + }); + + // Extend _eventIsOnActiveMenu to include the search entry context menu + // This prevents the main menu from closing when clicking on the context menu + let originalEventIsOnActiveMenu = this.menuManager._eventIsOnActiveMenu.bind(this.menuManager); + this.menuManager._eventIsOnActiveMenu = (event) => { + if (this.searchEntry._menu.isOpen && + this.searchEntry._menu.actor.contains(event.get_source())) { + return true; + } + return originalEventIsOnActiveMenu(event); + }; + + // Manual hover effect using direct style pseudo-class (no signals) + let contextMenu = this.searchEntry._menu; + let contextMenuItems = [contextMenu._copyItem, contextMenu._pasteItem]; + + let updateHoverState = () => { + if (!contextMenu.isOpen) { + for (let item of contextMenuItems) { + item.actor.change_style_pseudo_class('active', false); + } + return true; + } + + let [mouseX, mouseY] = global.get_pointer(); + for (let item of contextMenuItems) { + let [itemX, itemY] = item.actor.get_transformed_position(); + let [width, height] = item.actor.get_size(); + let isHovered = (mouseX >= itemX && mouseX <= itemX + width && + mouseY >= itemY && mouseY <= itemY + height); + item.actor.change_style_pseudo_class('active', isHovered); + } + return true; + }; + + // Start hover polling when main menu opens + this.menu.connect('open-state-changed', (menu, open) => { + if (open) { + Mainloop.timeout_add(50, updateHoverState); + } + }); this.searchEntry.set_secondary_icon(this._searchInactiveIcon); this.searchActive = false;