After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 64613 - focus handling (OutputOnly, ICCCM compliance)
focus handling (OutputOnly, ICCCM compliance)
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Backend: X11
1.3.x
Other other
: Normal normal
: ---
Assigned To: gtk-bugs
gtk-bugs
AP0
Depends on:
Blocks: 126727
 
 
Reported: 2001-11-15 08:15 UTC by Matthias Clasen
Modified: 2011-02-04 16:12 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
globally active input (8.44 KB, patch)
2003-11-20 22:32 UTC, Matthias Clasen
none Details | Review
alternative patch (10.75 KB, patch)
2003-12-04 21:00 UTC, Matthias Clasen
none Details | Review
patch as committed (16.99 KB, patch)
2003-12-10 23:55 UTC, Matthias Clasen
none Details | Review

Description Matthias Clasen 2001-11-15 08:15:48 UTC
There recently was some discussion of ICCCM focus handling on gtk-devel
and it was found that gtk windows always employ the ICCCM "Locally Active"
focus handling model. 

There apparently no way to create unfocusable (ie ICCCM "No Input" model)
windows, short of falling back to Xlib methods. 

I also noticed that there are two places where gtk/gdk call XSetInputFocus
with arguments which violate ICCCM conventions:

In gdkwindow-x11.c (gdk_window_focus):

      XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));

      /* There is no way of knowing reliably whether we are viewable so we
need
       * to trap errors so we don't cause a BadMatch.
       */
      gdk_error_trap_push ();
      XSetInputFocus (GDK_WINDOW_XDISPLAY (window),
                      GDK_WINDOW_XWINDOW (window),
                      RevertToNone,
                      timestamp);
      XSync (GDK_WINDOW_XDISPLAY (window), False);
      gdk_error_trap_pop ();


This is against section 4.1.7 of the ICCCM, which states that
Clients that invoke a SetInputFocus request should set the revert-to
argument to Parent .

Looking further, I find that gdk_window_focus() is called from
gtk_window_present() in the following way:

    gdk_window_focus (widget->window, gtk_get_current_event_time())

and gtk_get_current_event_time() may return CurrentTime if there is no
current event. But section 4.1.7 states that

Clients that use a SetInputFocus request must set the time field to the
timestamp of the event that caused them to make the attempt. This cannot be
a FocusIn event because they do not have timestamps. Clients may also
acquire the focus without a corresponding EnterNotify . Note that clients
must not use CurrentTime in the time field.
Comment 1 Matthias Clasen 2001-11-16 20:39:07 UTC
This is not actually a big deal. The problem case outlined in the
ICCCM is a reparenting WM which doesn't use save sets and then
crashes after the client has set the focus with revert-to None.
Quite theoretical, and looking at the X protocol specification of
revert-to Parent, it is not all that much safer, because the revert-to
value will change to None when the focus does actually revert to a
anchestor window. Thus, even with revert-to Parent, we can end up
with focus being None, it just takes to reverting steps instead of
one.
Comment 2 Owen Taylor 2001-11-19 19:06:34 UTC
Just committed a fix for the RevertToParent thing.

Mon Nov 19 13:56:45 2001  Owen Taylor  <otaylor@redhat.com>

        * gdk/x11/gdkwindow-x11.c (gdk_window_focus): Use 
        RevertToParent, not RevertToNone. (#64613, 
        Matthias Clasen)

I'm not worried about the timestamp issue, really. I think
the ICCCM should be read as "clients must not use CurrentTime
if they have any meaningful other time". If I'm presenting
the window in response to some incoming network traffic, there
are no race conditions to worry about.

One small problem you _can_ get is if the app itself first
sets the input focus with CurrentTime and then sets the
input focus to another window with a real (older timestamp).
What we do in GtkClipboard is retrieve real time stamps
from the server instead of using the CurrentTime and then
enforce increasing timestamps for all selection claiming
from within the app. This could be done here, but I have
a hard time coming with real examples where it would matter,
and I'd rather it keep it simple until someone has problems.

The OutputOnly issue is a API issue, and thus 2.2 fodder.
Until then, people will have to resort to Xlib.
Comment 3 bill.haneman 2003-11-18 12:52:09 UTC
Adding 'accessibility' keyword since assistive technologies like
magnifiers and onscreen keyboards frequently require output-only windows.
Comment 4 Matthias Clasen 2003-11-18 13:06:57 UTC
The necessary api here would probably be some boolean property


"accept_toplevel_focus" on GtkWindow plus the necessary 
getters/setters to propagate this down to where gdk calls XSetWMHints.
Comment 5 Owen Taylor 2003-11-18 15:23:18 UTC
*** Bug 126727 has been marked as a duplicate of this bug. ***
Comment 6 bill.haneman 2003-11-18 18:43:25 UTC
changing status whiteboard to 'AP0' since this has become a complete
blocker for GOK, due to changes in gtk+ internals.
Comment 7 Matthias Clasen 2003-11-20 22:31:32 UTC
Here is a proposal by Gregory Merchan to solve this by switching to
the globally active model for all gtk windows. "No Input" windows can
then be realized by 

      g_signal_connect (GTK_WINDOW (window), "take-focus-event",
			G_CALLBACK (gtk_true), NULL);

Gregory wants to use the globally active model for better handling of
focus in connection with DND, see
http://www.phys.lsu.edu/students/merchan/GNOME/Recommendations/DnD/

Comment 8 Matthias Clasen 2003-11-20 22:32:21 UTC
Created attachment 21671 [details] [review]
globally active input
Comment 9 padraig.obriain 2003-11-21 10:51:02 UTC
When I applied the attached patch I found that the gok main window no
longer receives focus. Is this expected? I had thought from the
previous comment that I would need to connect to the
"take-focus-event" signal.
Comment 10 Matthias Clasen 2003-11-21 11:46:08 UTC
No, this should not be the case. Everything should work as before, 
unless you connect to the take_focus_event signal. Could you perhaps 
debug where it is failing ?




Here is what should happen if you don't have a signal handler:




1. wm sends WM_TAKE_FOCUS


2. gdk wm protocol handler converts this into a GdkTakeFocus event


3. default handling in gtkmain.c for GTK_TAKE_FOCUS calls 
gtk_window_take_focus()


4. which calls gdk_window_take_focus()


5. which calls _gdk_x11_safe_set_input_focus() (or similar)


6. which performs the async equivalent of XSetInputFocus




the steps 2 - 4 are new here, previously the gdk wm protocol handler 
would directly call _gdk_x11_safe_set_input_focus()




Oh, you should also verify that the GOK window is actually using the


globally active model now:




xprop WM_PROTOCOLS should list WM_TAKE_FOCUS and xprop WM_HINTS should 
state that the InputHint is set to false.


Comment 11 padraig.obriain 2003-11-21 13:10:45 UTC
gok calls gdk_window_add_filter and in the filter function checks
whether a WM_TAKE_FOCUS message was sent. This seems to be an
alternative to specifing gtk_true as a "take-focus-event" signal
handler.
Comment 12 Matthias Clasen 2003-11-21 13:40:49 UTC
As long as you manage to ignore the WM_TAKE_FOCUS message...
Comment 13 bill.haneman 2003-11-21 15:33:46 UTC
yes, what we're doing is equivalent apparently to attaching gtk_true
to the wm-take-focus signal, if the above patch is applied.

The problem is that the current gdk model doesn't emit wm-take-focus
and thus the only way for us to explicitly reject focus is via
WM_TAKE_FOCUS, with a "no input" hint.  gdk is currently overwriting
the  "no input" hint and there's no way to explicitly tell gdk/gtk+
that a window should be no-input.

I think that the reason the patch makes our WM_TAKE_FOCUS code work
again has to do with the changes to gdk's input hint management.

Attaching to wm-take-focus as a gsignal is certainly cleaner than
doing the Xlib calls and ought to be more maintainable.

Comment 14 Matthias Clasen 2003-11-21 15:42:09 UTC
Yes, exactly. Setting the input hint to false is what makes this work, 
since it instructs the wm to not call XSetInputFocus on its own. 


Comment 15 Owen Taylor 2003-12-04 16:19:52 UTC
* What about portability? Is this setup really going to work
  on Win32 / OS-X / etc?

* What's the use case for doing anything other than simply
  not focusing the window? If that's the only use case,
  shouldn't we go with a simpler API?
Comment 16 Matthias Clasen 2003-12-04 19:24:59 UTC
* What about portability? Is this setup really going to work
  on Win32 / OS-X / etc?

No idea if it is possible to intercept focus-setting in this way
on Win32. But if it isn't, nothing should break. Apps have to handle
being given the focus anyway. They just won't get any TakeFocus events
on Win32 then. It's certainly going to work on XDarwin, and I don't
think we should worry about a native OS-X port at this point, should 
we ?

* What's the use case for doing anything other than simply
  not focusing the window? If that's the only use case,
  shouldn't we go with a simpler API?

Have you looked at Gregorys ideas (see the link above) ?




Comment 17 Matthias Clasen 2003-12-04 19:35:05 UTC
But we can certainly add a simple no-input api now and consider going
for globally active later. I'll try to come up with an alternative patch.
Comment 18 Matthias Clasen 2003-12-04 21:00:23 UTC
Created attachment 22113 [details] [review]
alternative patch
Comment 19 Matthias Clasen 2003-12-04 21:03:00 UTC
Here is an alternative patch which adds an accept_focus property on
gtkwindow plus two ways to set it on gdkwindow. Note that I still use
the globally active model, but ignore WM_TAKE_FOCUS to implement
no-input, since the actual no-input model seems to work less well with
the wms I tried. I guess other wms will have problems with the
globally active model...
Comment 20 bill.haneman 2003-12-04 22:42:26 UTC
cool, thanks a _lot_ for working on this Matthias.  The API patch
would solve the GOK problem too (as would the globally-active model
patch).
Comment 21 Owen Taylor 2003-12-10 00:23:51 UTC
The point about the take-focus not being portable is that
making a window non-focusable *is* possible on windows, but
you need to do it a different way.

I don't think the original patch is enough to do Gregory's ideas,
becuase it doesn't address the question of how the window
is getting the focus ... you can't distinguish say, a
user clicking on the titlebar then clicking on the content
area, from a click drag on the content.

You'd need some sort of protocol which said "here's a button
press event that you may want to use to start the focus" -
some of Gregory's later comments talk about using unused
fields in WM_TAKE_FOCUS to do this. 

Patch comments on the simple patch:

* "should receive input focus" would read better as
  "the input focus", and the documentation needs to explain
  what the input focus is.

* priv->accept_focus = 1;

should be '= TRUE'

* gtk_window_set_accept_focus() docs shouldn't reference
  the window manager, since that isn't a cross-platform
  concept. And "toggles" isn't really an appropriate term here - 
  I'd take toggle to mean a function that switches a setting
  every time you call it.

* I probably wouldn't bother adding the setting to 
  GdkWindowAttributes; setting it from the default value
  is rare enough that an extra X request won't hurt.
  BUt if you did, then gtk_window_realize() should take
  advantage of that.
 
* Cross-platform handling:

   Needs at least stubs for win32 and linux-fb so they
    keep compiling
   Should be pretty easy to implement for linux-fb, since
    all window "management" is done inside GTK+
   Probably best to simply file a bug to implement for win32;
    I think it's trivial but needs to be done by someone
    that can test.


   
Comment 22 Matthias Clasen 2003-12-10 23:54:44 UTC
I went ahead and committed a revised patch; I'll attach it below.
I was a bit at a loss how to explain "input focus". I've removed the
GdkWindowAttr additions and added stubs for Win32 and linux-fb. 
I've filed bug 129045 and bug 129043 to track the actual
implementation of "no input" windows for these backends.
Comment 23 Matthias Clasen 2003-12-10 23:55:45 UTC
Created attachment 22314 [details] [review]
patch as committed
Comment 24 padraig.obriain 2003-12-11 11:13:15 UTC
I find that I still need to call XSetWMHints for WM_TAKE_FOCUS or else
clicking on the window title focuses the window. Should this be dealt
with in gdk_window_set_accept_focus()?
Comment 25 Owen Taylor 2003-12-11 12:50:12 UTC
Test case?
Comment 26 bill.haneman 2003-12-11 12:57:00 UTC
Hi Owen: 
I know short unencumbered test cases are preferred.  But if you cvs co
GOK and build it, you can see the issue by removing the WM_TAKE_FOCUS
call in callbacks.c (on_window1_realize) and "clicking around a bit".
Comment 27 Matthias Clasen 2003-12-11 13:18:01 UTC
Bill, Padraig, can you verify that the gok window is actually switched 
to globally active ? See some comments above for what to look for.
Comment 28 Matthias Clasen 2003-12-11 13:19:12 UTC
And maybe also check if calling gtk_window_set_accept_focus()


separately works better, either before or after realizing the window ?
Comment 29 bill.haneman 2003-12-11 13:26:34 UTC
you've confused me: I thought the purpose of the patch was to prevent
the need to make windows globally active, ie. gdk is responsible for
not focussing them.

Note that things 'mostly' work when setting the property using
g_object_connect, so I don't see how calling set_accept_focus would
have a different effect.  i.e. the property is definitely getting set,
but correct behavior depends on also using WM_TAKE_FOCUS in the
client.  So it means that ATM the client still must use Xlib calls in
order to do the right thing.
Comment 30 bill.haneman 2003-12-11 13:42:02 UTC
I have confirmed that calling gtk_window_set_accept_focus in the
'realize' handler doesn't help.

But I understand the problem we are seeing: we call XSetWMProtocols()
which resets what gtk+ has already done; therefore we must add
WM_TAKE_FOCUS as one of those protocols.

But I think we no longer need the above Xlib call at all, so I will
remove it from GOK.

IOW I think this is client code error.
Comment 31 Matthias Clasen 2003-12-11 15:53:42 UTC
Yes, if you call XSetWMProtocols() you must take care not to remove


WM_TAKE_FOCUS, since that would change the input model gdk has 
selected. Regarding globally active: My superficial tests showed that 
some window managers seem to have problems with not giving focus to 
"no input" windows, while they don't have a problem to accept that a 
"globally active" window doesn't take focus. Therefore I've 
implemented "no input" by making the window globally active and never 
take focus when the wm sends WM_TAKE_FOCUS.