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 485016 - Two WM_TAKE_FOCUS messages on single click in the title of a window.
Two WM_TAKE_FOCUS messages on single click in the title of a window.
Status: RESOLVED OBSOLETE
Product: metacity
Classification: Other
Component: general
2.16.x
Other All
: Normal normal
: ---
Assigned To: Metacity maintainers list
Metacity maintainers list
Depends on:
Blocks:
 
 
Reported: 2007-10-09 12:06 UTC by Anton Tarasov
Modified: 2020-11-06 20:09 UTC
See Also:
GNOME target: ---
GNOME version: 2.15/2.16



Description Anton Tarasov 2007-10-09 12:06:05 UTC
Please describe the problem:
A decorated window having Globally Active focus model receives two WM_TAKE_FOCUS
when I click its title when the window is already focused.

Steps to reproduce:
1. Run the test provided. 
2. When the window is shown click its title ones.
3. You can repeat the 2nd step for several times.


#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char* argv[])
{
    Display* display;
    int screen_num;
    Window win;
    char *display_name = getenv("DISPLAY");

    display = XOpenDisplay(display_name);
    if (display == NULL) {
        fprintf(stderr, "%s: cannot connect to X server '%s'\n",
                argv[0], display_name);
        exit (-1);
    }

    screen_num = DefaultScreen(display);

    win = XCreateSimpleWindow(display, RootWindow(display, screen_num),
                              0, 0, 100, 100, 2,
                              BlackPixel(display, screen_num),
                              WhitePixel(display, screen_num));

    Atom wm_protocols = XInternAtom(display, "WM_PROTOCOLS", True);    
    Atom wm_take_focus = XInternAtom(display, "WM_TAKE_FOCUS", True);

    if (wm_protocols == None || wm_take_focus == None) {
        fprintf(stderr, "%s: connot retrieve the atoms\n", argv[0]);
        exit(-1);
    }

    if (!XSetWMProtocols(display, win, &wm_take_focus, 1)) {
        fprintf(stderr, "%s: connot set the WM_PROTOCOLS property\n", argv[0]);
        exit(-1);
    }

    XWMHints wm_hints;
    wm_hints.flags = InputHint;
    wm_hints.input = False;
    XSetWMHints(display, win, &wm_hints);

    XSelectInput(display, win, FocusChangeMask | ButtonPressMask);
    XMapWindow(display, win);

    XSync(display, False);

    int n = 0;
    XEvent event;
    while (True) {
        XNextEvent(display, &event);
        switch (event.type) {
            case ClientMessage:
            {
                XClientMessageEvent* cl = (XClientMessageEvent *)&event;
                if (cl->message_type == wm_protocols &&
                    cl->data.l[0] == wm_take_focus)
                {
                    fprintf(stderr, "event %d: WM_TAKE_FOCUS\n", n);
                    XSetInputFocus(display, win, RevertToParent, cl->data.l[1]);
                }
                break;
            }
            case FocusIn:
            {
                fprintf(stderr, "event %d: FocusIn\n", n);
                break;
            }
            case FocusOut:
            {
                fprintf(stderr, "event %d: FocusOut\n", n);
                break;
            }
            case ButtonPress:
            {
                fprintf(stderr, "event %d: ButtonPress\n", n);
                break;
            }
            default:
                break;
        }
        n++;
    }

    XCloseDisplay(display);
    return 0;
}




Actual results:
The window receives two WM_TAKE_FOCUS messages.

Expected results:
No WM_TAKE_FOCUS message, or at least one should be received.

Does this happen every time?
Yes.

Other information:
If I click to some other desktop window and then back in the window's
inside area - it will receive only one WM_TAKE_FOCUS message, that is correct.
If I click the title two WM_TAKE_FOCUS messages is received regardless
of whether the window was focused before or wasn't.
If I click in the window's inside area when the window is focused - the
window doesn't receive WM_TAKE_FOCUS that is correct.
Comment 1 Anton Tarasov 2007-10-09 12:11:22 UTC
I should have added that the problem is NOT reproducible in earlier
Metacity versions. I checked 2.8.x and 2.12.x.
Thus, this is a regression in behavior.
Comment 2 Elijah Newren 2007-10-10 00:47:21 UTC
(In reply to comment #1)
> I should have added that the problem is NOT reproducible in earlier
> Metacity versions. I checked 2.8.x and 2.12.x.
> Thus, this is a regression in behavior.

Really??  I was almost certain we had another bug report about this, filed back during 2.4 or 2.6...

The real root cause: X doesn't allow redirection of focus requests; i.e. it doesn't let the window manager be an input manager.  Deep design flaw in X, preventing us from checking if a window has focus (only X knows for sure)--so we instead focus it more than we need to sometimes.  However, we might be able to work around it better in this case.

The relevant code is metacity/src/frames.c:meta_frames_button_press_event() calls meta_window_focus() twice, indirectly (and meta_window_focus() calls meta_window_send_icccm_message).  The first is via calling meta_core_user_focus() which goes on to call meta_window_focus(), the second is via calling meta_core_begin_grab_op() (with op==META_GRAB_OP_MOVING) which calls meta_window_grab_all_keys() which calls meta_window_focus().
Comment 3 Anton Tarasov 2007-10-10 09:15:14 UTC
> Really??  I was almost certain we had another bug report about this, filed back
> during 2.4 or 2.6...
> 

I checked 2.4. There's no such problem there... (couldn't find 2.6)

> The real root cause: X doesn't allow redirection of focus requests; i.e. it
> doesn't let the window manager be an input manager.  Deep design flaw in X,
> preventing us from checking if a window has focus (only X knows for sure) --so

But why XGetInputFocus doesn't work for you?

Also, let me add additional info on the behavior.
I've slightly modified the testcase so that it requests focus only
the first time it receives WM_TAKE_FOCUS. Here's the code snipped:

==============================
    int n = 0;
    Bool isFocusSet = False;
    XEvent event;
    while (True) {
        XNextEvent(display, &event);
        switch (event.type) {
            case ClientMessage:
            {
                XClientMessageEvent* cl = (XClientMessageEvent *)&event;
                if (cl->message_type == wm_protocols &&
                    cl->data.l[0] == wm_take_focus)
                {
                    fprintf(stderr, "event %d: WM_TAKE_FOCUS\n", n);
                    if (!isFocusSet) {
                        fprintf(stderr, "         setting input focus\n", n);
                        XSetInputFocus(display, win, RevertToParent,
                                       cl->data.l[1]);
                        isFocusSet = True;
                    }
                }
                break;
            }
=============================

Here's the output:

- On start:

event 0: WM_TAKE_FOCUS              
         setting input focus
event 1: FocusIn

- On click in the title:

event 2: WM_TAKE_FOCUS
event 3: WM_TAKE_FOCUS
event 4: FocusOut
event 5: FocusIn

- On click in the inside area:

event 6: ButtonPress

The events 4,5 are really strange. Looks like the WM steals focus
and then brings it back...

(Anyway, thanks for the quick reply. Hope it will be resolved.)
Comment 4 Havoc Pennington 2007-10-10 16:51:46 UTC
Ignoring the bug and answering the tangential question: GetInputFocus (and focus events) aren't useful for deciding whether to set focus because it would create a race condition (it's always possible someone did SetInputFocus *after* you got the event or the GetInputFocus reply). When you call GetInputFocus you still don't know where the focus is; you only know where it just was.


Comment 5 Anton Tarasov 2007-10-11 07:13:53 UTC
Havoc,

Thanks, I see your point.
But in the scope of this I wonder how the following is possible.
With the test I've provided, when I click in the window (not in
the title) it receives:

a) WM_TAKE_FOCUS, ButtonPress - when focused
b) ButtonPress                - when unfocused

Thus, I suspect that the WM yet somehow knows if the window
is focused or not. Am I right?
Comment 6 Havoc Pennington 2007-10-11 18:06:08 UTC
iirc metacity does track the focus state (via focus events) and do some things differently depending on it. Whether that's correct or safe depends on the specifics, which I don't remember.
Comment 7 Anton Tarasov 2007-10-12 08:34:11 UTC
Well, as I understood (from the Newren's post) the issue is yet considered
to be a problem in metacity. If so, am I right expecting the status of the
bug to be changed to NEW?
Comment 8 André Klapper 2020-11-06 20:09:18 UTC
bugzilla.gnome.org is being replaced by gitlab.gnome.org. We are closing all old bug reports in Bugzilla which have not seen updates for many years.

If you can still reproduce this issue in a currently supported version of GNOME (currently that would be 3.38), then please feel free to report it at https://gitlab.gnome.org/GNOME/metacity/-/issues/

Thank you for reporting this issue and we are sorry it could not be fixed.