GNOME Bugzilla – Bug 343897
Orca's preferences should get focus when is activated.
Last modified: 2006-06-29 16:14:05 UTC
Please describe the problem: When the Orca preferences window is activated by pressing insert + space, the window doesn't get focus. Steps to reproduce: 1. Press insert + space 2. Orca preferences appears but "locus of focus" has not changed. 3. Press alt + tab to give focus to the preferences' window. Actual results: The preferences window appears but does not get focus. Expected results: The preferences' window should get focus wherever We are. What do you think? Does this happen every time? yes Other information: Using latest CVS with Ubuntu 6.06 system.
I believe this is an issue with the metacity window manager's attempt at smart focus stealing. Metacity was rather eager to refuse new windows from getting focus when they are activated, but I believe this has been fixed. I've tested this on a fresh install of Ubuntu 6.06 and I don't see the problem any more. It looks like you are still seeing the problem, though. :-(
I've got a small patch around for debugging focus problems with new windows that you can use. A few questions, though: Is insert+space a global keybinding, or one you press when the program already has focus? Is the process that gets the insert+space keybinding separate from the preferences window being launched?
Orca is a screen reader and is mostly an application that has no visible windows. Instead, it listens for AT-SPI events from all desktop applications (well, those that support the AT-SPI, anyway) via CORBA and presents their information in a non-visual way, such as through speech and/or braille. Orca also includes a magnification component, but it provides that support by speaking to a magnification service via CORBA. As such, the preferences UI is the primary GUI window that Orca will ever show. Insert+space is global in the sense that Orca will listen for keystrokes for the entire desktop, and will show the preferences UI when it detects Insert+space has been pressed no matter which application has focus. Thus, I guess the answers to your questions are that Orca launches the GUI window and Insert+space is handled in a global manner. If you can provide some sort of magic to make sure we can give the preferences GUI focus, it would be great! Thanks!
So, let's see if I understand you correctly (I'm not very sure that I am, so please correct me): It isn't orca that receives the insert+space keypress, rather it's one of any of the normal desktop applications -- and then those applications, via at-spi, tell orca that insert+space was pressed. Is that correct? (By way of contrast, the way I normally think of global keybindings is how metacity does it -- it actually grabs keys from each and every non-override-redirect window so that X reports those keypresses directly to metacity _instead_ of reporting them to the app; i.e. the app need not communicate anything to metacity and isn't even aware that any keybinding was pressed)
(In reply to comment #4) > So, let's see if I understand you correctly (I'm not very sure that I am, so > please correct me): It isn't orca that receives the insert+space keypress, > rather it's one of any of the normal desktop applications -- and then those > applications, via at-spi, tell orca that insert+space was pressed. Is that > correct? Pretty much right on, with the clarification that this is done at the toolkit/at-spi support layer in the application. For our intents and purposes, one can view the AT-SPI as an in-process application/toolkit layer sitting in between the higher-level application/toolkit logic and the keyboard, giving an out-of-process process such as Orca the first chance at consuming the events. If Orca consumes the events (which it does in the case of Insert+space), the AT-SPI support doesn't send the event to the higher-level application/toolkit logic. > (By way of contrast, the way I normally think of global keybindings is how > metacity does it -- it actually grabs keys from each and every > non-override-redirect window so that X reports those keypresses directly to > metacity _instead_ of reporting them to the app; i.e. the app need not > communicate anything to metacity and isn't even aware that any keybinding was > pressed) Understood. I think the AT-SPI plays similar tricks sometimes, and it may also eventually (if it doesn't already do so) support the XEvIE extension, which will allow assistive technologies such as Orca to get keyboard events at a much lower level.
(In reply to comment #5) > Pretty much right on, with the clarification that this is done at the > toolkit/at-spi support layer in the application. For our intents and purposes, > one can view the AT-SPI as an in-process application/toolkit layer sitting in > between the higher-level application/toolkit logic and the keyboard, giving an > out-of-process process such as Orca the first chance at consuming the events. Makes sense. So it looks something like app/gtkwidget-handling <- at-spi <- gdk <- X. Right? > If Orca consumes the events (which it does in the case of Insert+space), the > AT-SPI support doesn't send the event to the higher-level application/toolkit > logic. Okay, this is beginning to make sense now and I'm pretty sure I know where the bug is. To verify, though, what are the contents of the message sent by the toolkit via AT-SPI to orca when insert+space is pressed? I'm almost certain you have a missing bit of data here (unfortunately, an extremely common bit of data to ignore), but want to verify before jumping to conclusions to quickly. > Understood. I think the AT-SPI plays similar tricks sometimes, and it may > also eventually (if it doesn't already do so) support the XEvIE extension, > which will allow assistive technologies such as Orca to get keyboard events > at a much lower level. If I'm right above about the missing piece of data, I believe that something like this would fix this bug as a side-effect.
> Makes sense. So it looks something like app/gtkwidget-handling <- at-spi <- > gdk <- X. Right? Something like that, though I believe it can vary (e.g., if XEvIE is used, the AT-SPI logic gets closer to X). But the basic idea is that the at-spi is in there as a filter between the X server and the app/toolkit logic. > > If Orca consumes the events (which it does in the case of Insert+space), the > > AT-SPI support doesn't send the event to the higher-level application/toolkit > > logic. > > Okay, this is beginning to make sense now and I'm pretty sure I know where the > bug is. To verify, though, what are the contents of the message sent by the > toolkit via AT-SPI to orca when insert+space is pressed? I'm almost certain > you have a missing bit of data here (unfortunately, an extremely common bit of > data to ignore), but want to verify before jumping to conclusions to quickly. We just know the details of the keystroke: keycode, press/release, modifiers, keysym. If we're lucky, we can infer which application has focus.
(In reply to comment #7) > We just know the details of the keystroke: keycode, press/release, modifiers, > keysym. If we're lucky, we can infer which application has focus. Yes, you would have to be lucky, because determining which window has focus is a race condition at best (even for the window manager due to some braindead behavior in the design of X). Anyway, so far, sounds about right. Are those (keycode, press/release, modifiers, & keysym) the only details of the keystroke you know?
(In reply to comment #8) > > We just know the details of the keystroke: keycode, press/release, modifiers, > > keysym. If we're lucky, we can infer which application has focus. > > Yes, you would have to be lucky, because determining which window has focus is > a race condition at best (even for the window manager due to some braindead > behavior in the design of X). Anyway, so far, sounds about right. Are those > (keycode, press/release, modifiers, & keysym) the only details of the keystroke > you know? The complete details can be found by looking for "struct DeviceEvent" on this page: http://cvs.gnome.org/viewcvs/*checkout*/at-spi/idl/Accessibility_Registry.idl If you're looking for something in particular (your line of questioning makes me think you are ;-)), please let me know. Orca keeps track of various things, such as what it thinks is the active object/application, though these are in AT-SPI terms and not in raw-X11 terms.
Ah, you have the timestamp in that struct. That's great; most ignore that important field. What does the receiving end do with it?
For the intents and purposes of this discussion, Orca does nothing with the timestamp. Would you like it to do something? If so, just what is it exactly?
Absolutely, doing nothing with the timestamp is what I belive would cause this bug. You should use the timestamp to update the user_time of the preferences window before showing it. Here's the little explanation: When a user launches a new app/window, it should typically get focused when it appears. But if the user started using a different application between launch time and window-appears time, then the new window should not get focus. Metacity can only get this right if it knows the timestamp of the user event that caused the window to appear and the last time the user interacted with the currently focused window. In the case of this bug, the user pressed a key (shift+insert), gdk updates the user time of the application that had focus when this key was pressed, at-spi intercepts the keypress and sends a message to orca to open a window, and orca opens the preferences window. However, if orca does nothing to help gtk+ know the timestamp of the user interaction that caused it to be opened (i.e. neglects the timestamp sent by at-spi), gtk+ takes its best guess and uses the timestamp of the last time the user interacted with one of the orca windows. Thus, the orca preferences window has a really old timestamp, and the currently focused window has a very new timestamp; therefore, metacity won't transfer focus. To fix this, call gdk_x11_window_set_user_time() before showing the preferences window (you'll have to make sure the widget is realized, since this is at the gdk level).
Just been chatting with jdahlin on IRC. There is no Python binding for gdk_x11_window_set_user_time(). Elijah, is there any other way we can force the timestamp for the Orca configuration GUI window to be updated?
Are there python bindings to core X functions such as XChangeProperty()? If so, you could write your own version of such a function (see the first block of http://cvs.gnome.org/viewcvs/metacity/src/metacity-dialog.c?r1=1.11&r2=1.12 for an example of an app writing their own version of that gtk+ function back before gtk+-2.6 was released). I guess, as a last resort, you could write a separate program and call it with the X Window ID of the preferences dialog and the timestamp to update it with (assuming you've run gtk_widget_realize() on the window and haven't yet shown it) and then run that program when necessary. Sounds kind of ugly, though.
it was your choice to pick python as an implementation language...
Elijah, jdahlin informs me that they are there in a separate library called pyxlib, but it would "probably be quite tricky and have lots of issues". His suggestion is to wait and use the "soon-to-be-wrapped x11 specific functions in pygtk". I think we'll take that approach.
gtk.gdk.Window.set_user_time is now wrapped in CVS
Thanks Gustavo! I'll work on this next week.
Just to tell you where I am with this. I niavely thought I could install a copy of pygtk-2.9.2 on top of my GNOME 2.14 system and test out a fix for this problem using that. When I do the "./configure --prefix=/usr" of pygtk-2.9.2, it seems to go through nicely and summarises with: The following modules will be built: atk pango gtk with 2.8 API gtk.glade The following modules will NOT be built: pangocairo gtk.unixprint I then type "make". This fails with: ... /bin/bash ../libtool --mode=compile /opt/SUNWspro/bin/cc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/python2.4 -I/usr/include/pygtk-2.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I../../cairo-1.0.2/src -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -g -std=c9x -fno-strict-aliasing -c -o _gtk_la-gtkmodule.lo `test -f 'gtkmodule.c' || echo './'`gtkmodule.c /opt/SUNWspro/bin/cc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/python2.4 -I/usr/include/pygtk-2.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I../../cairo-1.0.2/src -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -g -std=c9x -fno-strict-aliasing -c gtkmodule.c -KPIC -DPIC -o .libs/_gtk_la-gtkmodule.o cc: Warning: illegal option -d=c9x cc: Warning: illegal option -fno-strict-aliasing "gtkmodule.c", line 33: cannot find include file: <pycairo.h> "gtkmodule.c", line 34: warning: old-style declaration or incorrect type for: Pycairo_CAPI_t "gtkmodule.c", line 34: syntax error before or at: * "gtkmodule.c", line 34: warning: old-style declaration or incorrect type for: Pycairo_CAPI "gtkmodule.c", line 201: undefined symbol: Pycairo_IMPORT cc: acomp failed for gtkmodule.c make[2]: *** [_gtk_la-gtkmodule.lo] Error 1 make[2]: Leaving directory `/export/home/richb/gnome/pygtk-2.9.2/gtk' Looks like I'll have to wait awhile until I've got a GNOME 2.15/16 system before I can try to fix this bug.
pygtk 2.9.2 is supposed to build with gtk 2.8, so i guess there is a bug somewhere preventing this. I did test compiling pygtk on breezy (gnome 2.14 based), but I guess i must have missed something... But please make sure you have pycairo development package installed and re-configure pygtk. In any case, the X11-specific functions are only enabled when compiling against gtk+ 2.9 because I have no idea (or don't have time to check) which of them are new in pygtk 2.9 and which are old.
Thanks Gustavo. I don't have pycairo on my system. I see from: http://cairographics.org/pycairo that the latest stable version is 1.0.2 and the latest development snapshot is 1.1.6. Presumably I need the latter? ... Just wanted to check as I don't want to blow my development system out of the water if I can help it. Thanks.
It should work with both pycairo 1.0.2 or 1.1.x.
I had to use pycairo 1.0.2 (to find the matching Cairo lib). I now have pycairo 1.0.2 installed and pygtk-2.9.2. Thanks! Onto the bug.
Created attachment 68125 [details] Patch that seems to fix the problem nicely. Thanks to Gustavo for creating a pygtk 2.9.3 snapshot for me that works with Gtk 2.8.X (to save me having to upgrade to the GTK 2.9/2.10 series). I've surronded the code with a try:/except: clause so that if this call isn't present with the version of pygtk that a user has installed, then is should hopefully fail gracefully. At some point, we will need to make Orca dependent upon pygtk 2.9.3, but this approach is probably okay for now.
Changes checked into CVS HEAD. Thanks for everybodies help with this one.
A couple of comments, since i'm listening on this bug anyway.. :) + try: + self.orcaSetupWindow.window.set_user_time(int(time.time())) time.time() returns the time in seconds as floating point; here you are rounding it to an integer, so it loses a lot of precision. I'm not sure the "X server time" has any relation to real "clock time" at all. Maybe you want to pass 0 here, which is equivalent to GDK_CURRENT_TIME in C?... or pass a timestamp you received from another gdk event that triggered this code?... + except: + debug.printException(debug.LEVEL_FINEST) Bare except: clauses are discouraged and will be disallowed in python3k; instead you should catch a specific exception, in this case AttributeError.
So changed. Many thanks! (And yes, I did test these changes before I checked it in. ;-) )
As Gustavo said, wall clock time has no relation to xserver time (the latter measures time in milliseconds since the xserver was started), so it's definitely not what you want. I also have a tirade about using 0/GDK_CURRENT_TIME, but you can ignore it if you took Gustavo's suggestion of using the real timestamp passed by at-spi. If you did that, ignore the rest of this comment. Otherwise: Don't use 0 (i.e. GDK_CURRENT_TIME) here. You're not sending a message to the Xserver saying "I don't know the time so just use whatever you know the current time to be." You're sending a message to the window manager which would have to ask the Xserver for the actual time. Even if it was the Xserver, though, using 0 would still cause a race condition. We have buggy workarounds in Metacity to try to make apps that use 0 work correctly as much as possible, but since the workarounds cause some nasty bugs in special cases we intend to remove that in the future. So, if you use 0, your app can break right now with a focus race condition, and _will_ be broken in the future when Metacity is modified (or when you happen to use another window manager). Using 0 gives you undefined behavior. Thanks for all your awesome work, everyone!
Okay, I'm now confused what I should put here. I originally had: self.orcaSetupWindow.window.set_user_time(int(time.time())) (which seemed to work nicely). Gustavo suggested I replace this with: self.orcaSetupWindow.window.set_user_time(0) (which also seems to work nicely). Now I'm being told mot to use 0, but use the real timestamp passed by at-spi. What real timestamp? If somebody would like to spell it out in words of one syllable or less I'd be grateful. Thanks.
It means that, if this code is triggered by receiving a gdk/X event, then you should use the timestamp found in the event structure. But probably at-spi communicates with orca using CORBA, in which case you don't have any event structure, in which case you have no choice but to keep using 0.
Yes, at-spi does use CORBA. The configuration GUI (for the situation we are trying to fixup) will have been started by the user typing Insert-<space>. I'll look around to see if there is a timestamp somewhere that I can use as this is happening. Thanks.
Rich: This was the reason for my questions to Willie. In comment 9, he linked to a file that seems to claim that a timestamp is already part of the struct that is passed (which is unusual). So, it looks like you just need to use the timestamp field of the DeviceEvent struct.
Created attachment 68173 [details] [review] Adjustment to first attemp to fix this. Thanks Elijah. I see what's going on now. We do get AT-SPI DeviceEvents coming in when you use types at the keyboard (in _processKeyboardEvent() in orca.py), but what was confusing me was that when Orca generates it's own KeyboardEvent() from them, it doesn't use the timestamp, but instead sets the time field to time.time(). What I've done is go back to _processKeyboardEvent() and save the timestamp field from each event (in orca.lastTimestamp), and I now use that in the call to set_user_time() in orca_gui_prefs.py
Changes checked into CVS HEAD. Thanks ago Gustavo and Elijah for help on this.