! Please note that this is a snapshot of our old Bugzilla server, which is read only since May 29, 2020. Please go to gitlab.xfce.org for our new server !
"Focus follows mouse" can be used to steal keyboard focus from clients that g...
Status:
RESOLVED: MOVED

Comments

Description Sam Varshavchik 2019-01-12 19:41:52 CET
"Focus model" is set to "Focus follows mouse" in Window Manager settings. "Automatically raise windows when they receive focus" is enabled.

With this configuration, even if a client grabs pointer AND keyboard focus, and now expects to exclusively receive and respond to all pointer and keyboard events, moving the pointer to another window still results in xfwm4 moving the keyboard focus to the other window, raising it on top of the client's window, then taking the keyboard focus away from an application that has successfully grabbed it.

This results in some counter-intuitive UI behavior. For example, an application window creates an OverrideDirect popup on top of itself, and grabs the pointer+keyborad (i.e. a combo-box popup). But, despite doing that, pointer activity may still result in another application's window getting raised on top of the application window, but behind the popup (since OverrideRedirect popups seem to be always stacked on top of non-overridden windows). The results are ugly -- another application window gets crammed between this application that has the pointer grabbed, and its popup. But, the application still continues to receive grabbed pointer and keyboard events.

If a window grabbed the pointer/keyboard, it's reasonable for the window to believe that it's the only one that's processing keyboard/pointer events, and it should not have pointer/keyboard focus taken away from it. Another argument is that nothing else should be receiving and responding to pointer events while somebody is holding a pointer grab -- including the window manager. That's what a pointer grab is supposed to be.

This behavior can be demonstrated with the following short example. This example waits two seconds, to get its top window drawn, then grabs the both the pointer AND the keyboard for 30 seconds and then logs all motion events and keyboard events.

Moving the pointer continues to log motion and keyboard events even when the pointer leaves the window that grabbed the pointer. But, moving  the pointer to another window results in another window now acquiring keyboard focus and xfwm4 raising that window, which could then cover the window that grabbed the pointer+keyboard -- and it continues to receive grabbed pointer events, apparently, but not keyboard events, it lost keyboard focus.

So, I have a window that grabbed both the pointer and the keyboard focus, but it still ends up losing the keyboard focus. Given that focus-follow-mouse affects both the pointer and keyboard events, a good argument can be made that this function should be disabled if some client has the pointer or the keyboard grabbed.

#include <xcb/xproto.h>
#include <unistd.h>
#include <poll.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

int main()
{
	xcb_connection_t *conn=xcb_connect(NULL, NULL);
	xcb_screen_t *screen=xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
	xcb_window_t wid=xcb_generate_id(conn);
	time_t t=time(NULL);
	time_t expiration=t+30;

	uint32_t event_mask[1];
	event_mask[0]=XCB_EVENT_MASK_POINTER_MOTION|XCB_EVENT_MASK_KEY_PRESS;

	xcb_create_window(conn,
			  XCB_COPY_FROM_PARENT,
			  wid,
			  screen->root,
			  100, 100,
			  100, 100,
			  10,
			  XCB_WINDOW_CLASS_INPUT_OUTPUT,
			  screen->root_visual,
			  XCB_CW_EVENT_MASK,
			  event_mask);

	xcb_map_window(conn, wid);
	xcb_flush(conn);
	sleep(2);
	xcb_grab_pointer(conn, 0, wid,
			 XCB_EVENT_MASK_BUTTON_PRESS |
			 XCB_EVENT_MASK_BUTTON_RELEASE |
			 XCB_EVENT_MASK_ENTER_WINDOW |
			 XCB_EVENT_MASK_LEAVE_WINDOW |
			 XCB_EVENT_MASK_POINTER_MOTION,
			 XCB_GRAB_MODE_ASYNC,
			 XCB_GRAB_MODE_ASYNC,
			 XCB_NONE,
			 XCB_NONE,
			 XCB_TIME_CURRENT_TIME);
	printf("Ok\n");
	xcb_flush(conn);

	while (t < expiration)
	{
		xcb_generic_event_t *event=xcb_poll_for_event(conn);

		if (!event)
		{
			struct pollfd pfd;

			pfd.fd=xcb_get_file_descriptor(conn);
			pfd.events=POLLIN|POLLHUP;

			if (poll(&pfd, 1, (expiration-t)*1000) < 0)
				break;

			if (pfd.revents & POLLHUP)
				break;
			t=time(NULL);
			continue;
		}
		if ((event->response_type & ~0x80) == XCB_MOTION_NOTIFY)
		{
			xcb_motion_notify_event_t *me=
				(xcb_motion_notify_event_t *)event;

			printf("(%d, %d)\n",
			       (int)me->event_x,
			       (int)me->event_y);
		}

		if ((event->response_type & ~0x80) == XCB_KEY_PRESS)
		{
			printf("Key press\n");
		}
		free(event);
	}
	return 0;
}
Comment 1 Git Bot editbugs 2020-05-29 12:24:34 CEST
-- GitLab Migration Automatic Message --

This bug has been migrated to xfce.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.xfce.org/xfce/xfwm4/-/issues/315.

Please create an account or use an existing account on one of our supported OAuth providers. 

If you want to fork to submit patches and merge requests please continue reading here: https://docs.xfce.org/contribute/dev/git/start#gitlab_forks_and_merge_requests

Also feel free to reach out to us on the mailing list https://mail.xfce.org/mailman/listinfo/xfce4-dev

Bug #15035

Reported by:
Sam Varshavchik
Reported on: 2019-01-12
Last modified on: 2020-05-29

People

Assignee:
Olivier Fourdan
CC List:
0 users

Version

Version:
4.13.1

Attachments

Additional information