-
Notifications
You must be signed in to change notification settings - Fork 203
do LayoutUpdate for menus with no entries #548
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
This also fixes Dropbox's tray icon menu not opening. |
indicatorStatusIcon.js
Outdated
if (this.menu.numMenuItems) { | ||
this.menu.toggle(); | ||
} else { | ||
// update menu if there's no entries | ||
this._updateMenu(); | ||
// wait for menu update | ||
this._waitForDoubleClick().catch(logError); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm unsure here, shouldn't be:
if (this.menu.numMenuItems) { | |
this.menu.toggle(); | |
} else { | |
// update menu if there's no entries | |
this._updateMenu(); | |
// wait for menu update | |
this._waitForDoubleClick().catch(logError); | |
} | |
// Try to update the menu if there are no entries. | |
if (!this.menu.numMenuItems) | |
this._updateMenu(); | |
this.menu.toggle(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you.
I think it should be.
It seems that this.menu.toggle()
is called inside this._waitForDoubleClick()
so does not need to be called here.
Mhmh, since I can't personally reproduce this with QQ, not sure if that happens after logging in or if I can test it before. |
The system tray icon in Blueman exhibits a similar persistence issue - once the application launches, the context menu associated with the tray icon becomes static and does not refresh to reflect state changes. After launching Blueman, performing Bluetooth enable/disable operations through the interface will not update the visual state of the tray icon The icon state only refreshes after either:
This behavioral pattern suggests a fundamental refresh mechanism limitation in the tray icon implementation. Similar behavior can be expected in analogous scenarios where system tray components require dynamic state updates without full application/desktop environment reloads. |
A minimal example to reproduce the issue. The tray should have import gi
from gi.repository import AyatanaAppIndicator3 as AppIndicator3
from gi.repository import Gtk
class IndicatorApp:
def __init__(self):
# Create the main window
self.window = Gtk.Window(title="Login Example")
self.window.set_default_size(200, 100)
self.window.connect("destroy", self.on_quit)
# Create a button
self.button = Gtk.Button(label="Login")
self.button.connect("clicked", self.on_login_clicked)
self.window.add(self.button)
# Create the app indicator
self.indicator = AppIndicator3.Indicator.new(
"indicator-example",
"system-run-symbolic", # Default icon
AppIndicator3.IndicatorCategory.APPLICATION_STATUS)
self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)
# Initial empty menu
self.menu = Gtk.Menu()
self.indicator.set_menu(self.menu)
# Show the window
self.window.show_all()
# Track login state
self.logged_in = False
def on_login_clicked(self, widget):
if not self.logged_in:
# Update button text
self.button.set_label("Logout")
# Update tray menu
self.update_tray_menu()
self.logged_in = True
else:
# Logout action
self.button.set_label("Login")
self.clear_tray_menu()
self.logged_in = False
def update_tray_menu(self):
# Clear existing menu items
self.clear_tray_menu()
# Create new menu items
menu = Gtk.Menu()
# Add logout item
item_logout = Gtk.MenuItem(label="Logout")
item_logout.connect("activate", self.on_logout_clicked)
menu.append(item_logout)
# Add separator
menu.append(Gtk.SeparatorMenuItem())
# Add quit item
item_quit = Gtk.MenuItem(label="Quit")
item_quit.connect("activate", self.on_quit)
menu.append(item_quit)
# Show all menu items
menu.show_all()
# Set the new menu
self.indicator.set_menu(menu)
def clear_tray_menu(self):
# Create an empty menu
menu = Gtk.Menu()
self.indicator.set_menu(menu)
def on_logout_clicked(self, widget):
# Reset to login state
self.button.set_label("Login")
self.clear_tray_menu()
self.logged_in = False
def on_quit(self, widget=None):
Gtk.main_quit()
if __name__ == "__main__":
app = IndicatorApp()
Gtk.main() |
Yes I believe that there should be better solutions to this. I was unable to inspect what exactly happened during the communication between QQ and StatusNotifierHost but with Bustle I can see how it is going now.
It seems that QQ does not have the problem any more, probably because it does not provide an empty menu before login. Thanks to DerryAlex who provided another minimal reproduce. |
The code changes in this PR are different since @AmionSky's comment that this fixes the Dropbox tray icon, so I just wanted to chime in and say that the latest revision still works. I applied it in a minimalist way to v43 in Debian 12 (Gnome 43.9): diff --git a/dbusMenu.js.bak b/dbusMenu.js
index a30502a..f74899e 100644
--- a/dbusMenu.js.bak
+++ b/dbusMenu.js
@@ -470,14 +470,14 @@ var DBusClient = GObject.registerClass({
_onSignal(_sender, signal, params) {
if (signal === 'LayoutUpdated') {
- if (!this._active) {
+ if (!this._active && this.getRoot()?.getChildren().length) {
this._flagLayoutUpdateRequired = true;
return;
}
this._requestLayoutUpdate();
} else if (signal === 'ItemsPropertiesUpdated') {
- if (!this._active) {
+ if (!this._active && this.getRoot()?.getChildren().length) {
this._flagItemsUpdateRequired = true;
return;
} Now, when I boot my system and log in, the Dropbox tray icon works when I click it. I used to have to lock the screen and then unlock it before the icon would work. |
@3v1n0 - any chance this could be re-reviewed/merged? |
This PR (partially) fixes #494.
Edit:
This problem is caused by the "empty menus":
LayoutUpdate
signal, classDBusClient
only requests a layout update whenthis._active
istrue
(indicating the menu is currently open), or it is delayed untilthis._active
becomestrue
(when the menu is opened later).this._active
is only set totrue
when anopen-state-changed
signal is emitted, which is triggered by opening the popup menu.this._active
keepsfalse
, so the delayedLayoutUpdate
handler never runs.QQ is an IM app who provides no menu entries before user logged in, and updates it when logged in. But it probably does not emit a
LayoutUpdated
signal before updating menu so its tray icon menu can never open until appindicator restarts (by disabling the extension or ending gnome session). Here we try updating entries before opening an empty menu. Only primary click and secondary click will trigger an update.Wondering if there are better solutions...