As first discussed in InkscapeTamed, keyboard events are sent to the event context handlers (both global in event-context.c and tool-specific e.g. select-context.c) ONLY when the mouse is over the canvas.
Simple experiment: move a shape by arrows. This works while the mouse cursor is over the document window but stops as soon as you move mouse away from it, even if the document window still has focus. Global verbs like + and - and ctrl-q always work. We cannot however make tool-specific shortcuts global verbs.
- Mental writes:
Grabbing focus between widgets is accomplished via gtk_widget_grab_focus(). The widget will need to have the GTK_CAN_FOCUS flag set, however. I've taken care of the latter half in desktop.c now (setting the CAN_FOCUS widget flag).
I guess what remains is just determining when it would be appropriate to call gtk_widget_grab_focus() on the canvas widget.
- bb writes:
I cannot make it work. I added
into sp_desktop_widget_new in desktop.c. For debugging, I also added
gtk_signal_connect (GTK_OBJECT (&(dtw->canvas->widget)), "event", GTK_SIGNAL_FUNC (sp_canvas_event_handler), &(dtw->canvas->widget));
and put some debug output into sp_canvas_event_handler. With or without the grab, it looks like the canvas widget gets keypresses, but does not pass them on to the event context. That is, it does pass it to the event context but only when the mouse is within the canvas.
Maybe we need to grab focus on the event context, not on the canvas? But how to do that? I think the event context is not a GTK widget.
- Mental responds:
Well, grab_focus() isn't like a window "grabbing" focus; gtk_widget_grab_focus() is the normal mechanism for widgets handing focus off to one another.
_new() likely isn't the time to call it, because its effect is not persistent.
So it would need to be called e.g. when the canvas widget is clicked or moused over or something like that.
Thinking about it, I _believe_ (I will have to double-check) that events are actually passed to the event context by the enclosing [ventBox (GtkDesktopWidget is a descendant of GtkEventBox).
- and then adds:
To be honest I still don't totally understand how events are handed off to event contexts in Sodipodi/Inkscape. :/
> Maybe we need to grab focus on the event context, not on the canvas? But how > to do that? I think the event context is not a GTK widget.
Well, ultimately _some_ widget must receive the events and passing them on to the event context. We need to figure out which widget that is/should be.
UPDATE: OK, I think I fixed that. Now the canvas always gets all keys, including arrows, space, esc etc. (i.e. not only global verb shortcuts) so long as the document window has focus. This closes a sore "known problem" from 0.36 release notes.
I'm not sure if my fix is "correct" but it seems to work. Previously, event contexts received events only from the "acetate" item on the canvas (this is an invisible item covering the entire canvas), and this item obviously can only have focus when mouse is over it. We have tried putting event grab on the canvas widget, but this apparently did not affect the acetate which, not being a GTK widget, cannot have a grab. My solution is simply to call sp_desktop_root_handler() from within the sp_desktop_widget_event() handler (which receives all desktop widget events regardless of mouse position) but only for GDK_KEY_PRESS events and only if the desktop's canvas has no current item (because in that case, an item handler must be called instead of root handler, and I don't need to do that anyway because this can only happen when the mouse is over the canvas).