Hello,

I have kept the story below for the record and attached the testcase
again in case it could be useful.

So the issue is that DoFocusEvents does not send focus events if
from == to, which happens here because the focus-grab.c is calling
XSetInputFocus to set the input focus (as expected for a window manager)
and it happens that it's that window which is requesting a grab, so from
== to. But since it is a grab, we should really emit the focus event, so
that listeners (notably XI listeners) are aware of the grabbing taking
place.  I have posted a patch fixing it titled "dix: always send focus
event on grab change" on xorg-devel@lists.x.org for review.

Cheers,
Samuel

Samuel Thibault, le ven. 22 déc. 2017 01:01:04 +0100, a ecrit:
> Samuel Thibault, on jeu. 21 déc. 2017 18:21:39 +0100, wrote:
> > Samuel Thibault, on jeu. 21 déc. 2017 17:50:54 +0100, wrote:
> > > One additionnal piece of information: it seems that what makes compiz
> > > have the issue (compared to my simple X root event listener) is the call
> > > to
> > > 
> > > XSetInputFocus (s->dpy (), priv->id, RevertToPointerRoot, CurrentTime);
> > > 
> > > on the window that after that acquires the grab.
> > 
> > Here are reproducers.
> > 
> > - First run focus-grab on a bare X server
> > - then run grab, which opens a window on the top left corner.
> > - Move the mouse to it.
> >   -> in focus-grab the enter notify handler calls XSetInputFocus [*]
> > - press the g key  
> > 
> > The result is this: On the ./grab side:
> > 
> > focus out 4194305 0
> > focus in 4194305 0
> > 0: ||
> > 1: |g|
> > 0:1|g|
> > res 0
> > 
> > I.e. it got the 'g' keypress event, and successfully called XGrabKeyboard.
> > And on the ./focus-grab side:
> > 
> > started
> > create 4194305
> > enter 4194305 0
> > 1
> > core focus out 4194305 0
> > core focus out 38 0
> > core focus out 38 0
> > core focus in 38 0
> > core focus in 4194305 0
> > focus out 6 0
> > key press 7 7 42 0
> > key release 7 7 42 0
> > 
> > I.e. it saw the creation of the window, catched entering the window
> > and set XSetInputFocus, which generate focus events, then saw the 'g'
> > keypress (77 is my numlock) but didn't see any grab-related focus
> > events. That's my concern.
> 
> And without the XSetInputFocus call, one gets
> 
> 1: |g|
> 0:1|g|
> res 0
> focus out 4194305 1
> focus in 4194305 1
> 
> and
> 
> started
> create 4194305
> enter 4194305 0
> key press 7 7 42 0
> core focus out 4194305 1
> core focus out 38 1
> core focus out 38 1
> core focus in 38 1
> core focus in 4194305 1
> focus out 6 1
> key release 7 7 42 0
> 
> i.e. there really is the grab information.
> 
> BTW, this is X server core 1.19.5 (Debian Buster up to date)
> 
> Samuel

-- 
Samuel
>       dvips -o $@ $<     
Faut faire gffe de pas te couper avec ton truc, t'as mis des ciseaux ($<)
partout :))
-+- Dom in Guide du linuxien pervers - "J'aime pas les Makefile !" -+-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XInput2.h>
#include <X11/XKBlib.h>

int main (int argc, char **argv) {
	Display *mydisplay, *mydisplay2;
	Window mywindow;

	XEvent myevent;
	KeySym mykey;

	XSizeHints myhint;
	XComposeStatus status;
	memset(&status,0,sizeof(status));

	int myscreen;
	unsigned long myforeground, mybackground, valuemask;
	XSetWindowAttributes xswa;
	int i;
	char text[10];
	int done;

	mydisplay=XOpenDisplay("");
	myscreen=DefaultScreen(mydisplay);
	mybackground=WhitePixel(mydisplay, myscreen);
	myforeground=BlackPixel(mydisplay, myscreen);

	myhint.x=0; myhint.y=0;
	myhint.width=400; myhint.height=400;
	myhint.flags=PPosition|PSize;

	mywindow=XCreateSimpleWindow(mydisplay, DefaultRootWindow (mydisplay), myhint.x, myhint.y, myhint.width, myhint.height, 5 /*border*/, myforeground, mybackground);

	XSetWindowBackgroundPixmap(mydisplay, mywindow, None);
	XMapRaised(mydisplay, mywindow);

	XSelectInput(mydisplay, mywindow, FocusChangeMask | KeyPressMask);

	while(1) {
		XNextEvent (mydisplay, &myevent);
		switch(myevent.type) {
			case MappingNotify:
				XRefreshKeyboardMapping(&myevent.xmapping);
				break;
			case ButtonPress:
				fprintf(stderr,"button press\n");
				break;
			case KeyPress:
				i = XLookupString(&myevent.xkey, text, 10, &mykey, &status);
				fprintf(stderr,"%d: |%s|\n",i,text);
				if (i == 1 /*len*/ && text[0] == 'q') done = 1;
				char buf[128];
				int foo;
				if (XkbTranslateKeySym(mydisplay, &mykey, 0, buf, sizeof(buf), &foo))
					fprintf(stderr,"%d:%d|%s|\n", foo, strlen(buf), buf);
				if (myevent.xkey.keycode == 42)
				{
					int res;
					res = XGrabKeyboard (mydisplay, mywindow, True, GrabModeAsync, GrabModeAsync, CurrentTime);
					fprintf(stderr,"res %d\n", res);
				}
				else if (myevent.xkey.keycode == 43)
				{
					int res;
					res = XUngrabKeyboard(mydisplay, CurrentTime);
					fprintf(stderr,"res %d\n", res);
				} else if (myevent.xkey.keycode == 38)
					exit(1);
				break;
			case KeyRelease:
				break;
			case FocusIn:
				fprintf(stderr, "focus in %d %d\n", myevent.xfocus.window, myevent.xfocus.mode);
				break;
			case FocusOut:
				fprintf(stderr, "focus out %d %d\n", myevent.xfocus.window, myevent.xfocus.mode);
				break;
			default:
				fprintf(stderr,"mesg %d\n", myevent.type);
		}
	}
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XInput2.h>
#include <X11/XKBlib.h>

#define XI

char hello[]="hello, World.";
char hi[]="Hi!";

int main (int argc, char **argv) {
	Display *mydisplay;
	Window mywindow;

	XEvent myevent;
	KeySym mykey;

	XComposeStatus status;
	memset(&status,0,sizeof(status));

	int i;
	char text[10];
	int done;

	mydisplay=XOpenDisplay("");

	mywindow = DefaultRootWindow(mydisplay);

	XSelectInput(mydisplay, DefaultRootWindow(mydisplay),
		  SubstructureNotifyMask   |
		  StructureNotifyMask      |
		  EnterWindowMask          |
		  FocusChangeMask          );

	int xi_opcode = -1;

#ifdef XI
	int first_event, first_error;
	if (XQueryExtension(mydisplay, "XInputExtension", &xi_opcode, &first_event, &first_error)) 
	{
		int major = 2;
		int minor = 1;
		if (XIQueryVersion(mydisplay, &major, &minor) != BadRequest) {
			XIEventMask eventmask;
			unsigned char mask[XIMaskLen (XI_LASTEVENT)] = { 0 };

			eventmask.deviceid = XIAllDevices;
			eventmask.mask_len = sizeof(mask);
			eventmask.mask = mask;

			XISetMask (mask, XI_KeyPress);
			XISetMask (mask, XI_KeyRelease);
			XISetMask (mask, XI_ButtonPress);
			XISetMask (mask, XI_ButtonRelease);
			XISetMask (mask, XI_Motion);
			XISetMask (mask, XI_FocusIn);
			XISetMask (mask, XI_FocusOut);
			XISelectEvents (mydisplay, mywindow, &eventmask, 1);
		}
	}
#endif

	done=0;
	printf("%d\n", XSetInputFocus (mydisplay, None, RevertToParent, CurrentTime));
	fprintf(stderr,"started\n");
	while(done==0) {
		XNextEvent (mydisplay, &myevent);
		switch(myevent.type) {
			case KeyPress:
				i = XLookupString(&myevent.xkey, text, 10, &mykey, &status);
				fprintf(stderr,"%d: |%s|\n",i,text);
				if (i == 1 /*len*/ && text[0] == 'q') done = 1;
				char buf[128];
				int foo;
				if (XkbTranslateKeySym(mydisplay, &mykey, 0, buf, sizeof(buf), &foo))
					fprintf(stderr,"%d:%ld|%s|\n", foo, strlen(buf), buf);
				break;
			case KeyRelease:
				break;
			case FocusIn:
				fprintf(stderr, "core focus in %ld %d\n", myevent.xfocus.window, myevent.xfocus.mode);
				break;
			case FocusOut:
				fprintf(stderr, "core focus out %ld %d\n", myevent.xfocus.window, myevent.xfocus.mode);
				break;
			case EnterNotify:
				fprintf(stderr, "enter %ld %d\n", myevent.xcrossing.window, myevent.xcrossing.mode);
				//printf("%d\n", XSetInputFocus (mydisplay, myevent.xcrossing.window, RevertToPointerRoot, CurrentTime));
				printf("%d\n", XSetInputFocus (mydisplay, myevent.xcrossing.window, RevertToParent, CurrentTime));
				break;
			case LeaveNotify:
				fprintf(stderr, "leave %ld %d\n", myevent.xcrossing.window, myevent.xcrossing.mode);
				break;
			case GenericEvent:
				if (myevent.xcookie.extension == xi_opcode) {
					XGetEventData(mydisplay, &myevent.xcookie);
					XIRawEvent *xiRawEv = (XIRawEvent *) myevent.xcookie.data;
					XIDeviceEvent *xiDevEv = (XIDeviceEvent *) myevent.xcookie.data;
					XIEnterEvent *xiEntEv = (XIEnterEvent *) myevent.xcookie.data;
					switch (myevent.xcookie.evtype) {
						case XI_KeyPress:
							fprintf(stderr,"XI key press %d %d %d %x\n", xiRawEv->deviceid, xiRawEv->sourceid, xiRawEv->detail, xiDevEv->flags);
							break;
						case XI_KeyRelease:
							fprintf(stderr,"XI key release %d %d %d %x\n", xiRawEv->deviceid, xiRawEv->sourceid, xiRawEv->detail, xiDevEv->flags);
							break;
						case XI_FocusIn:
							fprintf(stderr, "XI focus in %d %d\n", xiEntEv->detail, xiEntEv->mode);
							break;
						case XI_FocusOut:
							fprintf(stderr, "XI focus out %d %d\n", xiEntEv->detail, xiEntEv->mode);
							break;
					}
					XFreeEventData(mydisplay, &myevent.xcookie);
				} else {
					fprintf(stderr,"generic mesg %d %d\n", myevent.xcookie.extension, xi_opcode);
				}
				break;
			case CreateNotify:
				{
				Window win = myevent.xcreatewindow.window;
				fprintf(stderr, "create %ld\n", win);
				XSelectInput(mydisplay, win, FocusChangeMask | SubstructureNotifyMask |EnterWindowMask          );
				break;
				}
			case MapRequest:
				XMapWindow(mydisplay, myevent.xmaprequest.window);
				break;
		}
	}
}
_______________________________________________
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to