Re: Programatically activate menu like a mouse click

2017-02-26 Thread John Lane

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

2017-02-24 Thread Colomban Wendling
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

2017-02-24 Thread John Lane
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

2017-02-24 Thread John Lane

> 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

2017-02-23 Thread Colomban Wendling
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

2017-02-23 Thread Eric Cashon via gtk-app-devel-list

 

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

2017-02-23 Thread John Lane
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

2017-02-23 Thread Norbert de Jonge
> 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

2017-02-23 Thread John Lane
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