Gtk.StatusIcon and gtk.Menu on Windows

I have a cross-platform application that has gtk.StatusIcon sitting in a tray and a right-click context menu. The problem is that on Windows machines the menu layout is terrible. The top of the menu starts with the mouse pointer, so most of the menu goes below the bottom of the screen. Then it can be scrolled and used, but for the user it is a little painful.

Another related question: is it possible for the menu to disappear if the user clicks on another location on the screen?

+4
source share
3 answers

To avoid this scrolling issue on Windows, you need to replace gtk.status_icon_position_menu with None in the popup menu signal callback.

 def popup_menu_cb(status_icon, button, activate_time, menu): menu.popup(None, None, None, button, activate_time) 

The menu will be displayed on the mouse cursor, but as all Windows programs do.

I don’t know how to hide it, though ... the only thing I found for work was to click on the menu button and release it from the outside .: P

+3
source

You can hide the popup when the mouse moves away by enabling the pop_notify and enter_notify events in the popup. Then use them to set and clear the timestamp. Then, in the timer callback created with gobject.timeout_add (), check to see if the mouse has been in the popup menu for a certain amount of time. If it then hides () the popup and clears the timer.

The following are the event and timer callbacks that I use:

 . . . self.mouse_in_tray_menu = None gobject.timeout_add(500, self.check_hide_popup) . . . def on_tray_menu_enter_notify_event(self, widget, event, data = None): self.mouse_in_tray_menu = None def on_tray_menu_leave_notify_event(self, widget, event, data = None): self.mouse_in_tray_menu = event.time + 1 # Timeout in 1 sec def check_hide_popup(self, data = None): if self.mouse_in_tray_menu and self.mouse_in_tray_menu < time.time(): self.tray_menu.hide() self.mouse_in_tray_menu = None return True # Keep the timer callback running 

You do not need to constantly work with a timer, but it is easier, and I also use it for other things. The calls to enter_notify and leave_notify are somewhat unstable, so a timer is needed.

By the way, this is really only necessary on Windows, because on Linux you can click elsewhere and the popup will close.

+2
source

I found a solution to fix the pop-up menu will not hide problems in Windows.

Just add the following code (my code is in C, but you can change it to python or something else) before appearing in the menu:

 GtkWidget *hidden_window; hidden_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_resizable (GTK_WINDOW (hidden_window), FALSE); gtk_window_set_decorated (GTK_WINDOW (hidden_window), FALSE); gtk_window_set_skip_taskbar_hint (GTK_WINDOW (hidden_window), TRUE); gtk_window_set_skip_pager_hint (GTK_WINDOW (hidden_window), TRUE); gtk_widget_set_size_request (hidden_window, 0, 0); gtk_window_set_transient_for (GTK_WINDOW (hidden_window), GTK_WINDOW (widget)); //widget is your main window, this is to hide dummy window from taskbar gtk_window_set_position (GTK_WINDOW (hidden_window), GTK_WIN_POS_MOUSE); gtk_widget_set_events (hidden_window, GDK_FOCUS_CHANGE_MASK); g_signal_connect (G_OBJECT (hidden_window), "focus-out-event", G_CALLBACK (on_hidden_window_focus_out), NULL); gtk_widget_show_all (hidden_window); gtk_widget_grab_focus (hidden_window); 

also add this function:

 static void on_hidden_window_focus_out(GtkWidget *widget, GdkEventFocus *event, gpointer data) { gtk_widget_destroy (widget); } 

The idea is to create a 1x1 top-level window at the mouse position and capture the focus and add the kill function when focusing.

+1
source

All Articles