Re: Programatically activate menu like a mouse click
Ok, so I have made a little progress on this, albeit in a one step forward, two steps back kind-of way. This code in my `keybinder_callback` half-works: import Xlib from Xlib import X from Xlib.display import Display from Xlib.ext.xtest import fake_input display = Display() mpos = display.screen().root.query_pointer()._data display.screen().root.warp_pointer(x,5) display.sync() fake_input(display,X.ButtonPress,1, X.CurrentTime, X.NONE, x, 5) display.sync() fake_input(display,X.ButtonRelease,1) display.screen().root.warp_pointer(mpos['root_x'], mpos['root_y']) It partially activates the menu bar (the first item is highlighted but the drop-down does not appear) and generates the following error message: Gdk-CRITICAL **: Window 0x1e7c660 has not been made visible in GdkSeatGrabPrepareFunc After that, nothing works. However, the exact same code in a stand-alone program executed in a second terminal window works absolutely fine: #!/usr/bin/env python import Xlib from Xlib import X from Xlib.display import Display from Xlib.ext.xtest import fake_input display = Display() mpos = display.screen().root.query_pointer()._data display.screen().root.warp_pointer(1605,5) display.sync() fake_input(display,X.ButtonPress,1, X.CurrentTime, X.NONE, 1605, 5) display.sync() fake_input(display,X.ButtonRelease,1) display.screen().root.warp_pointer(mpos['root_x'], mpos['root_y']) display.sync() So I tried this: import time ... def keybinder_callback(self, keystr, user_data): time.sleep(0.2) x = self.get_position().root_x+5 display = Display() mpos = display.screen().root.query_pointer()._data display.screen().root.warp_pointer(x,5) display.sync() fake_input(display,X.ButtonPress,1, X.CurrentTime, X.NONE, x, 5) display.sync() fake_input(display,X.ButtonRelease,1) display.screen().root.warp_pointer(mpos['root_x'], mpos['root_y']) display.sync() Guess what? It's nasty, but it works! Once I discovered the sleep, I found that this also works (I tried this before but it exhibited the same problem described above): def keybinder_callback(self, keystr, user_data): time.sleep(0.2) run("xdotool mousemove %d 10 click 1 mousemove restore" % (self.get_position().root_x+5) , shell=True) Without the `sleep(0,2)`, I get the above critical error. So there is some timing issue that I need to consider. Any ideas what this is and how to cater for it without the `sleep` sledehammer ? ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Re: Programatically activate menu like a mouse click
Le 24/02/2017 à 10:24, John Lane a écrit : > On 23/02/17 21:02, Colomban Wendling wrote: > >> >> Sounds odd to do that manually. Do you know about mnemonic keys? >> Basically if you mark some part of the label to be the mnemonic letter, >> you'll be able to trigger that element with Alt+letter. >> >> Additionally, F10 already pops up the first menu of the window's menubar. >> > > I sent a reply to Eric's message with an example of what I am doing. > Whay you suggest is valid for a "window" application that has the input > focus but I am trying to write a "dock" application that isn't focussed. > Sorry I should have made that clearer. OK. But it's also actually what e.g. MATE's panel (which is a dock too) uses: https://github.com/mate-desktop/mate-panel/blob/master/mate-panel/panel-menu-bar.c#L415 >> self.menubar1.select_item(self.menuitem1) > > Thanks for that tip - I tried it and (see my other msg) it selects the > first menu item but the app doesn't respond after that. There really seems to be something funky in relation to that Keybinder. GTK emits warning when poping up the menu, I guess because it doesn't see the "current event". Initially: > (menu2.py:24105): Gtk-WARNING **: no trigger event for menu popup And then, if playing with arrows: > (menu2.py:24105): Gdk-CRITICAL **: Window 0x55a411e7d660 has not been made > visible in GdkSeatGrabPrepareFunc > > (menu2.py:24105): Gdk-CRITICAL **: Window 0x55a411e7d660 has not been made > visible in GdkSeatGrabPrepareFunc > > (menu2.py:24105): Gdk-CRITICAL **: Window 0x55a411e7d660 has not been made > visible in GdkSeatGrabPrepareFunc > > (menu2.py:24105): Gdk-CRITICAL **: gdk_window_get_window_type: assertion > 'GDK_IS_WINDOW (window)' failed > > (menu2.py:24105): Gtk-CRITICAL **: _gtk_widget_captured_event: assertion > 'WIDGET_REALIZED_FOR_EVENT (widget, event)' failed > > (menu2.py:24105): Gtk-CRITICAL **: _gtk_widget_captured_event: assertion > 'WIDGET_REALIZED_FOR_EVENT (widget, event)' failed > > (menu2.py:24105): Gtk-CRITICAL **: _gtk_widget_captured_event: assertion > 'WIDGET_REALIZED_FOR_EVENT (widget, event)' failed I can't help with that, but I think it's related with the issue ;) Cheers, Colomban ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Re: Programatically activate menu like a mouse click
On 23/02/17 21:02, Colomban Wendling wrote: > > Sounds odd to do that manually. Do you know about mnemonic keys? > Basically if you mark some part of the label to be the mnemonic letter, > you'll be able to trigger that element with Alt+letter. > > Additionally, F10 already pops up the first menu of the window's menubar. > I sent a reply to Eric's message with an example of what I am doing. Whay you suggest is valid for a "window" application that has the input focus but I am trying to write a "dock" application that isn't focussed. Sorry I should have made that clearer. > self.menubar1.select_item(self.menuitem1) Thanks for that tip - I tried it and (see my other msg) it selects the first menu item but the app doesn't respond after that. ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Re: Programatically activate menu like a mouse click
> Give this a try. It might be close to what you are after. Thanks Eric. That works, however it is slightly different to what I need. Firstly, my app is a dock containing nothing but a menu bar, so it has no "window" as such. Secondly, its key binding only works when its window has the focus. I need to globally bind a key so that it works regardless of the active application and this is why I have used the keybinder module. I have distilled an example and uploaded it as https://gist.github.com/db6bf5247058e32ffa5d794af37b80a3 It's very similar to your example except I create a dock and have been trying to use XML to generate menu items as well as doing it in code like my example shows. My example runs and the menus work as long as they are "activated" with the mouse, after which the mouse or keyboard can be used to navigate the menu. The key binding works, it just doesn't activate the menu. You can see the three things I tried in the code, two of them are commented out. The bound key is "Menu" (right-hand bottom of keyboard near right-alt) and the binding works when another application window is active. I just need the keybinder_callback to also perform similar "activation" of the menu. I don't even care whether it displays an initial submenu or just keyboard-focusses the menubar - the aim is to be able to hit the bound "Menu" key and then operate the menu with the keyboard (like I can after activating it with the mouse). I have also tried 'select_item' (as suggested by Colomban) which does select the first item in the menu bar but after that the app locks up and nothing responds, not even with the mouse. Many thanks, John ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Re: Programatically activate menu like a mouse click
Le 23/02/2017 à 15:57, John Lane a écrit : > […] > > The UIManager provides the menu bar, a few items in the bar each leading > to menus containing a few items. The user can click operate the menu > with a mouse and selecting a menu item triggers a callback that prints > the name of the selected item. Nothing special thus far, but it works. > > Once the user has clicked on a menu bar item with the mouse, she can > then navigate the menu with the keyboard (or continue using the mouse). > > I have wired up a global key binding using the 'keybinder' module and > receive a callback when a mapped key is pressed. Sounds odd to do that manually. Do you know about mnemonic keys? Basically if you mark some part of the label to be the mnemonic letter, you'll be able to trigger that element with Alt+letter. Additionally, F10 already pops up the first menu of the window's menubar. > […] > > How can I trigger the menu activation (like a mouse click does) ? Read https://developer.gnome.org/gtk3/stable/GtkMenuShell.html and use Gtk.MenuShell.select_item(). As menubars and menus are shells, assuming Eric's sample, use: self.menubar1.select_item(self.menuitem1) instead of manually poping the menu up. But still, you should consider using memnonics Regards, Colomban ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Re: Programatically activate menu like a mouse click
Hi John, Give this a try. It might be close to what you are after. Eric #!/usr/bin/python import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, Gdk class MainWindow(Gtk.Window): def __init__(self): Gtk.Window.__init__(self, title="Menu Popup") self.set_default_size(200, 100) self.set_position(Gtk.WindowPosition.CENTER) self.menubar1 = Gtk.MenuBar() self.menu1 = Gtk.Menu() self.menuitem1 = Gtk.MenuItem("Menu") self.menuitem1.set_submenu(self.menu1) self.menuitem2 = Gtk.MenuItem("Save") self.menuitem2.connect("activate", self.save_file) self.menuitem3 = Gtk.MenuItem("Print") self.menuitem3.connect("activate", self.print_file) self.menu1.append(self.menuitem2) self.menu1.append(self.menuitem3) self.menubar1.append(self.menuitem1) self.connect("key-press-event", self.key_pressed) self.grid = Gtk.Grid() self.grid.attach(self.menubar1, 0, 0, 1, 1) self.add(self.grid) def save_file(self, menuitem2): print("Save File") def print_file(self, menuitem3): print("Print File") def key_pressed(self, widget, event): print("Key Pressed") print(str(event.keyval)) self.menu1.popup(None, None, None, None, 0, event.time) return False win = MainWindow() win.connect("delete-event", Gtk.main_quit) win.show_all() Gtk.main() ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Re: Programatically activate menu like a mouse click
On 23/02/17 15:23, Norbert de Jonge wrote: > I would guess with: > https://developer.gnome.org/gtk3/stable/GtkMenu.html#gtk-menu-popup-at-widget Thanks, I have 3.22.5. I had tried `gtk-menu-popup-at-widget` but it didn't work. I've tried lots of combinations to try and get it to work without success. Like this: self.menu.popup_at_widget(self.anchor,Gdk.Gravity.SOUTH_WEST,Gdk.Gravity.NORTH_WEST,None) I tried with self.menu being the first menu out of the uibuilder and also with menu that I built manually (using Gtk.Menu, Gtk.MenuItem, etc) and attached to the menubar. Both kinds of menu appear as expected and work with the mouse just fine but they are different: * The uimanager menu is * The manually built menu is This leads to different behaviour when I call popup_at_widget. If I pull 'self.menu' out of UIManager then I get an error: self.menu.popup_at_widget(self.anchor, Gdk.Gravity.SOUTH_WEST,Gdk.Gravity.NORTH_WEST,None) AttributeError: 'ImageMenuItem' object has no attribute 'popup_at_widget' Whereas if I use the manually built menu I get warnings: Gtk-WARNING **: no trigger event for menu popup Warning: g_object_set_data: assertion 'G_IS_OBJECT (object)' failed self.menu.popup_at_widget(self.anchor,Gdk.Gravity.SOUTH_WEST, Gdk.Gravity.NORTH_WEST,None) It makes no difference whether self.anchor is the box widget or the menubar widget pulled from UI manager. The menubar widget is The box widget is box > It's available for GTK+ 3.22 and up, so I cannot test it to verify. My other thought is that popup_at_widget is only 3.22+. I wanted to find a solution that worked in Gtk3 and Gtk2 because I am evaluating both of them (there are things I need that can't be done using Gtk3 without falling back on Xlib). So perhaps the above isn't the way, and there is another way to achieve this... I appreciate any help. John ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Re: Programatically activate menu like a mouse click
> How can I trigger the menu activation (like a mouse click does) ? I would guess with: https://developer.gnome.org/gtk3/stable/GtkMenu.html#gtk-menu-popup-at-widget It's available for GTK+ 3.22 and up, so I cannot test it to verify. This should tell you your GTK+ version: $ pkg-config --modversion gtk+-3.0 Best regards, Norbert ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Programatically activate menu like a mouse click
I am trying to write a small test app using Python and Gtk+3 It's basically a bar across the top of the display that contains a menu implemented as a Gtk.Window containing a Gtk.Bar containing a menu bar populated using UIManager. Essentially this (where 'self' is an object derived from `Gtk.Window`): box = Gtk.Box(); menubar = uimanager.get_widget("/MenuBar") self.menu = menubar box.pack_start(menubar, False, False, 0) self.add(box) The UIManager provides the menu bar, a few items in the bar each leading to menus containing a few items. The user can click operate the menu with a mouse and selecting a menu item triggers a callback that prints the name of the selected item. Nothing special thus far, but it works. Once the user has clicked on a menu bar item with the mouse, she can then navigate the menu with the keyboard (or continue using the mouse). I have wired up a global key binding using the 'keybinder' module and receive a callback when a mapped key is pressed. I want to activate the menu in the same way as that initial mouse click. I can't work out how to do that, despite reading and searching for days! Here's my keybinder callback (it is called when the key is hit but it does not activate the menu): def keybinder_callback(self, keystr, user_data): print("Handling", keystr, user_data) print("Event time:", Keybinder.get_current_event_time()) self.menu.popup(None,None,None,None,1, Keybinder.get_current_event_time()) How can I trigger the menu activation (like a mouse click does) ? ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list