Re: Entry / TextBuffer that does not listen to accelerators?

Am Freitag 30 September 2005 17:04 schrieb muppet:
Stephan Brunner said:
I am not able to enter any 'u' into the Entry.

The reason this should work is, that the active widget gets the input.
If the widget does not handle it, it passes it on to it's parent. And so
on up to the window, which handles the accels.

Not quite; key events are delivered first to the toplevel window (an X
quirk), and propagated from there to child widgets. 
gtk_window_key_press_event() looks like this:


Which means that window-wide mnemonics and accelerators take precedence
over per-widget keystrokes.  And, if you think about it, it *has* to work
that way, or something like a TextView would eat all of the keys that are
supposed to be menu accelerators.

Reading this, I wonder even more why I can't get it to work the way I
want to. Is there some subtle mistake or usage-error in my code?

No.  Your key is handled by the UI manager, which means, by the logic
above, it takes precedence over the widget's handling of the event.  In
fact, your Entry or TextView never even gets the key-press-event.

This sort of clash is the reason for using modifiers on accelerators in the
first place.  The problem would be easily solved by making your accel be
"<Ctrl>U" instead of just "U"... but since that's not what you asked...

In this instance you need to have the widget get the first crack at the
unadorned key.  The guys on gtk-app-devel-list or in #gtk+ will probably
know better than i, but here's what i would try:

a) Don't put the accelerator in the UIManager descriptions, but handle it
by hand in key_press_event on the toplevel window, connected by
signal_connect_after().  By removing it from the UI manager, it doesn't get
handled in the accelerator table, and by having it connected _after, your
handler runs *after* the key has been propagated to the other widgets,
which gives the TextView and Entry first crack at it.  The drawback is that
you lose the helpful accelerator hint in the menu.

Hmm, since I want to provide some sort of "plug-in" mechanism for the 
application, I'm quite happy about the UI manager and its convenient way of 
extending the user interface. Not only would I lose the accelerator hint, but 
also the possibility to automatically "register" a plug-in action with its 


b) Leave the accelerator in the UIManager, and add special code in your
action handler to route the event as necessary.

  sub u_action {
      # if the key focus is currently on the toplevel window, we may
      # need to do further key routing:
      my $widget = Gtk2->get_event_widget (Gtk2->get_current_event);
      if ($widget->isa ('Gtk2::Window')) {
          # check the type of the widget that currently has focus:
          my $focus_widget = $widget->get_focus;
          if ($focus_widget &&
              ($focus_widget->isa ('Gtk2::Editable') ||
               $focus_widget->isa ('Gtk2::TextView'))) {
              # he needs this event more than we do.
              $focus_widget->event (Gtk2->get_current_event);
      print "$count: This is sub u_action...\n";

I don't like this approach very much because it feels fragile, and requires
placing this behavior in all of the handlers for unadorned accels, rather
than just connecting them in a different place.  On the other hand, you get
your handlers through UIManager, which is nice.

Yeah, even though it's clear what happens here, it somehow doesn't feel 
"complete" enough.

Well, there doesn't seem to be a "straight forward" solution like 
$widget->set_listen_to_accels(FALSE), so I will have to think twice about 
going for <Ctrl>U... I just like the VIM-approach more than the Emacs one;-)

Thank you very much for the deep insight - at least I now understand why it's 
not working "out of the box"!


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]