xcb: Asynchronous pointer grab not propagating events

Clash Royale CLAN TAG#URR8PPP
up vote
2
down vote
favorite
I am trying to make an image appear under my cursor whenever I click on my desktop. I decided to use xcb to accomplish this. I figured I should capture the pointer from the root window (I don't really know a better way to do it), because I always want the image to appear, no matter where I click. The application that displays the image should not interfere with my normal workflow.
Here is how I capture the pointer so far:
#include <X11/Xutil.h>
#include <X11/Xlib-xcb.h>
#include <X11/Xutil.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb.h>
#include <xcb/xproto.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
void setup(xcb_connection_t *connection)
xcb_generic_error_t *err;
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
xcb_void_cookie_t grab_cookie = xcb_grab_button(connection, True, screen->root, XCB_NONE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY);
xcb_generic_error_t *error = xcb_request_check(connection, grab_cookie);
if (error != NULL)
xcb_disconnect(connection);
perror("could not subscribe to events on a window, bailing out");
exit(1);
free(error);
xcb_flush(connection);
int main(int argc, char *argv)
xcb_generic_event_t *e;
Display *dpy = XOpenDisplay(NULL);
xcb_connection_t *connection = XGetXCBConnection(dpy);
setup(connection);
while ((e = xcb_wait_for_event(connection)))
switch(e->response_type & ~0x80)
case XCB_BUTTON_PRESS:
printf("Click.n");
break;
default:
break;
free(e);
xcb_ungrab_pointer(connection, XCB_TIME_CURRENT_TIME);
The code line that grabs the cursor is in the setup method:
xcb_void_cookie_t grab_cookie = xcb_grab_button(connection, True, screen->root, XCB_NONE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY);
As far as I can tell by "autocorrecting" man xcb_grab_button, my pointer events should not be influenced if I put XCB_GRAB_MODE_ASYNC as the fifth argument to the function (the manual says something different, but it is generally quite poor, so I would be very surprised if it weren't by mistake). However, this is not the case: When I click, the click simply gets swallowed by my application and, e.g., Firefox does not react to it.
How can grab the cursor such that my click events do not get eaten? If such a feature does not exist in X, would you recommend that I simply "resend" the click events or is there a better option? My window manager is i3, in case this information changes anything.
linux x11 xorg xcb
add a comment |Â
up vote
2
down vote
favorite
I am trying to make an image appear under my cursor whenever I click on my desktop. I decided to use xcb to accomplish this. I figured I should capture the pointer from the root window (I don't really know a better way to do it), because I always want the image to appear, no matter where I click. The application that displays the image should not interfere with my normal workflow.
Here is how I capture the pointer so far:
#include <X11/Xutil.h>
#include <X11/Xlib-xcb.h>
#include <X11/Xutil.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb.h>
#include <xcb/xproto.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
void setup(xcb_connection_t *connection)
xcb_generic_error_t *err;
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
xcb_void_cookie_t grab_cookie = xcb_grab_button(connection, True, screen->root, XCB_NONE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY);
xcb_generic_error_t *error = xcb_request_check(connection, grab_cookie);
if (error != NULL)
xcb_disconnect(connection);
perror("could not subscribe to events on a window, bailing out");
exit(1);
free(error);
xcb_flush(connection);
int main(int argc, char *argv)
xcb_generic_event_t *e;
Display *dpy = XOpenDisplay(NULL);
xcb_connection_t *connection = XGetXCBConnection(dpy);
setup(connection);
while ((e = xcb_wait_for_event(connection)))
switch(e->response_type & ~0x80)
case XCB_BUTTON_PRESS:
printf("Click.n");
break;
default:
break;
free(e);
xcb_ungrab_pointer(connection, XCB_TIME_CURRENT_TIME);
The code line that grabs the cursor is in the setup method:
xcb_void_cookie_t grab_cookie = xcb_grab_button(connection, True, screen->root, XCB_NONE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY);
As far as I can tell by "autocorrecting" man xcb_grab_button, my pointer events should not be influenced if I put XCB_GRAB_MODE_ASYNC as the fifth argument to the function (the manual says something different, but it is generally quite poor, so I would be very surprised if it weren't by mistake). However, this is not the case: When I click, the click simply gets swallowed by my application and, e.g., Firefox does not react to it.
How can grab the cursor such that my click events do not get eaten? If such a feature does not exist in X, would you recommend that I simply "resend" the click events or is there a better option? My window manager is i3, in case this information changes anything.
linux x11 xorg xcb
add a comment |Â
up vote
2
down vote
favorite
up vote
2
down vote
favorite
I am trying to make an image appear under my cursor whenever I click on my desktop. I decided to use xcb to accomplish this. I figured I should capture the pointer from the root window (I don't really know a better way to do it), because I always want the image to appear, no matter where I click. The application that displays the image should not interfere with my normal workflow.
Here is how I capture the pointer so far:
#include <X11/Xutil.h>
#include <X11/Xlib-xcb.h>
#include <X11/Xutil.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb.h>
#include <xcb/xproto.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
void setup(xcb_connection_t *connection)
xcb_generic_error_t *err;
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
xcb_void_cookie_t grab_cookie = xcb_grab_button(connection, True, screen->root, XCB_NONE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY);
xcb_generic_error_t *error = xcb_request_check(connection, grab_cookie);
if (error != NULL)
xcb_disconnect(connection);
perror("could not subscribe to events on a window, bailing out");
exit(1);
free(error);
xcb_flush(connection);
int main(int argc, char *argv)
xcb_generic_event_t *e;
Display *dpy = XOpenDisplay(NULL);
xcb_connection_t *connection = XGetXCBConnection(dpy);
setup(connection);
while ((e = xcb_wait_for_event(connection)))
switch(e->response_type & ~0x80)
case XCB_BUTTON_PRESS:
printf("Click.n");
break;
default:
break;
free(e);
xcb_ungrab_pointer(connection, XCB_TIME_CURRENT_TIME);
The code line that grabs the cursor is in the setup method:
xcb_void_cookie_t grab_cookie = xcb_grab_button(connection, True, screen->root, XCB_NONE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY);
As far as I can tell by "autocorrecting" man xcb_grab_button, my pointer events should not be influenced if I put XCB_GRAB_MODE_ASYNC as the fifth argument to the function (the manual says something different, but it is generally quite poor, so I would be very surprised if it weren't by mistake). However, this is not the case: When I click, the click simply gets swallowed by my application and, e.g., Firefox does not react to it.
How can grab the cursor such that my click events do not get eaten? If such a feature does not exist in X, would you recommend that I simply "resend" the click events or is there a better option? My window manager is i3, in case this information changes anything.
linux x11 xorg xcb
I am trying to make an image appear under my cursor whenever I click on my desktop. I decided to use xcb to accomplish this. I figured I should capture the pointer from the root window (I don't really know a better way to do it), because I always want the image to appear, no matter where I click. The application that displays the image should not interfere with my normal workflow.
Here is how I capture the pointer so far:
#include <X11/Xutil.h>
#include <X11/Xlib-xcb.h>
#include <X11/Xutil.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb.h>
#include <xcb/xproto.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
void setup(xcb_connection_t *connection)
xcb_generic_error_t *err;
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
xcb_void_cookie_t grab_cookie = xcb_grab_button(connection, True, screen->root, XCB_NONE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY);
xcb_generic_error_t *error = xcb_request_check(connection, grab_cookie);
if (error != NULL)
xcb_disconnect(connection);
perror("could not subscribe to events on a window, bailing out");
exit(1);
free(error);
xcb_flush(connection);
int main(int argc, char *argv)
xcb_generic_event_t *e;
Display *dpy = XOpenDisplay(NULL);
xcb_connection_t *connection = XGetXCBConnection(dpy);
setup(connection);
while ((e = xcb_wait_for_event(connection)))
switch(e->response_type & ~0x80)
case XCB_BUTTON_PRESS:
printf("Click.n");
break;
default:
break;
free(e);
xcb_ungrab_pointer(connection, XCB_TIME_CURRENT_TIME);
The code line that grabs the cursor is in the setup method:
xcb_void_cookie_t grab_cookie = xcb_grab_button(connection, True, screen->root, XCB_NONE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY);
As far as I can tell by "autocorrecting" man xcb_grab_button, my pointer events should not be influenced if I put XCB_GRAB_MODE_ASYNC as the fifth argument to the function (the manual says something different, but it is generally quite poor, so I would be very surprised if it weren't by mistake). However, this is not the case: When I click, the click simply gets swallowed by my application and, e.g., Firefox does not react to it.
How can grab the cursor such that my click events do not get eaten? If such a feature does not exist in X, would you recommend that I simply "resend" the click events or is there a better option? My window manager is i3, in case this information changes anything.
linux x11 xorg xcb
linux x11 xorg xcb
edited Oct 11 '17 at 3:15
asked Oct 11 '17 at 3:10
PawkyPenguin
696110
696110
add a comment |Â
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
2
down vote
accepted
I solved the mystery. Apparently XCB_GRAB_MODE_ASYNC does not do what I thought it would: The (correct) xcb_grab_pointer manual says that the pointer event processing continues normally. I thought that this would refer to the events being propagated to other clients, but this is not the case. The events are still only heard by my application. To propagate the events, they need to be replayed after receival:
xcb_generic_event_t *e;
xcb_generic_error_t *err;
xcb_connection_t *connection = xcb_connect(NULL, NULL);
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
xcb_void_cookie_t grab_cookie = xcb_grab_button_checked(connection, True, screen->root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY);
xcb_generic_error_t *error = xcb_request_check(connection, grab_cookie);
if (error != NULL)
xcb_disconnect(connection);
perror("could not subscribe to events on a window, bailing out");
exit(1);
free(error);
do {
xcb_allow_events(connection, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME);
e = xcb_poll_for_event(connection);
if(!e)
continue;
switch(e->response_type & EVENT_MASK)
case XCB_BUTTON_RELEASE:
case XCB_BUTTON_PRESS:
printf("Hello.n");
break;
default:
break;
free(e);
while(1);
xcb_ungrab_pointer(connection, XCB_TIME_CURRENT_TIME);
Before the do-while-loop, the pointer press and release for the index1 button are grabbed. The fifth argument has to be XCB_GRAB_MODE_SYNC so that the X server queues events until xcb_allow_events is called (the Xlib manual, man XGrabPointer, gives detailed information, though I wouldn't rely on it in detail, given that it is not for XCB). The subsequent call to xcb_allow_events within the while-loop thaws (unfreezes) the pointer event processing. Passing the XCB_ALLOW_REPLAY_POINTER parameter replays the button events.
It's important to use xcb_poll_for_event within the loop, although I don't fully understand why.
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
accepted
I solved the mystery. Apparently XCB_GRAB_MODE_ASYNC does not do what I thought it would: The (correct) xcb_grab_pointer manual says that the pointer event processing continues normally. I thought that this would refer to the events being propagated to other clients, but this is not the case. The events are still only heard by my application. To propagate the events, they need to be replayed after receival:
xcb_generic_event_t *e;
xcb_generic_error_t *err;
xcb_connection_t *connection = xcb_connect(NULL, NULL);
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
xcb_void_cookie_t grab_cookie = xcb_grab_button_checked(connection, True, screen->root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY);
xcb_generic_error_t *error = xcb_request_check(connection, grab_cookie);
if (error != NULL)
xcb_disconnect(connection);
perror("could not subscribe to events on a window, bailing out");
exit(1);
free(error);
do {
xcb_allow_events(connection, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME);
e = xcb_poll_for_event(connection);
if(!e)
continue;
switch(e->response_type & EVENT_MASK)
case XCB_BUTTON_RELEASE:
case XCB_BUTTON_PRESS:
printf("Hello.n");
break;
default:
break;
free(e);
while(1);
xcb_ungrab_pointer(connection, XCB_TIME_CURRENT_TIME);
Before the do-while-loop, the pointer press and release for the index1 button are grabbed. The fifth argument has to be XCB_GRAB_MODE_SYNC so that the X server queues events until xcb_allow_events is called (the Xlib manual, man XGrabPointer, gives detailed information, though I wouldn't rely on it in detail, given that it is not for XCB). The subsequent call to xcb_allow_events within the while-loop thaws (unfreezes) the pointer event processing. Passing the XCB_ALLOW_REPLAY_POINTER parameter replays the button events.
It's important to use xcb_poll_for_event within the loop, although I don't fully understand why.
add a comment |Â
up vote
2
down vote
accepted
I solved the mystery. Apparently XCB_GRAB_MODE_ASYNC does not do what I thought it would: The (correct) xcb_grab_pointer manual says that the pointer event processing continues normally. I thought that this would refer to the events being propagated to other clients, but this is not the case. The events are still only heard by my application. To propagate the events, they need to be replayed after receival:
xcb_generic_event_t *e;
xcb_generic_error_t *err;
xcb_connection_t *connection = xcb_connect(NULL, NULL);
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
xcb_void_cookie_t grab_cookie = xcb_grab_button_checked(connection, True, screen->root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY);
xcb_generic_error_t *error = xcb_request_check(connection, grab_cookie);
if (error != NULL)
xcb_disconnect(connection);
perror("could not subscribe to events on a window, bailing out");
exit(1);
free(error);
do {
xcb_allow_events(connection, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME);
e = xcb_poll_for_event(connection);
if(!e)
continue;
switch(e->response_type & EVENT_MASK)
case XCB_BUTTON_RELEASE:
case XCB_BUTTON_PRESS:
printf("Hello.n");
break;
default:
break;
free(e);
while(1);
xcb_ungrab_pointer(connection, XCB_TIME_CURRENT_TIME);
Before the do-while-loop, the pointer press and release for the index1 button are grabbed. The fifth argument has to be XCB_GRAB_MODE_SYNC so that the X server queues events until xcb_allow_events is called (the Xlib manual, man XGrabPointer, gives detailed information, though I wouldn't rely on it in detail, given that it is not for XCB). The subsequent call to xcb_allow_events within the while-loop thaws (unfreezes) the pointer event processing. Passing the XCB_ALLOW_REPLAY_POINTER parameter replays the button events.
It's important to use xcb_poll_for_event within the loop, although I don't fully understand why.
add a comment |Â
up vote
2
down vote
accepted
up vote
2
down vote
accepted
I solved the mystery. Apparently XCB_GRAB_MODE_ASYNC does not do what I thought it would: The (correct) xcb_grab_pointer manual says that the pointer event processing continues normally. I thought that this would refer to the events being propagated to other clients, but this is not the case. The events are still only heard by my application. To propagate the events, they need to be replayed after receival:
xcb_generic_event_t *e;
xcb_generic_error_t *err;
xcb_connection_t *connection = xcb_connect(NULL, NULL);
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
xcb_void_cookie_t grab_cookie = xcb_grab_button_checked(connection, True, screen->root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY);
xcb_generic_error_t *error = xcb_request_check(connection, grab_cookie);
if (error != NULL)
xcb_disconnect(connection);
perror("could not subscribe to events on a window, bailing out");
exit(1);
free(error);
do {
xcb_allow_events(connection, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME);
e = xcb_poll_for_event(connection);
if(!e)
continue;
switch(e->response_type & EVENT_MASK)
case XCB_BUTTON_RELEASE:
case XCB_BUTTON_PRESS:
printf("Hello.n");
break;
default:
break;
free(e);
while(1);
xcb_ungrab_pointer(connection, XCB_TIME_CURRENT_TIME);
Before the do-while-loop, the pointer press and release for the index1 button are grabbed. The fifth argument has to be XCB_GRAB_MODE_SYNC so that the X server queues events until xcb_allow_events is called (the Xlib manual, man XGrabPointer, gives detailed information, though I wouldn't rely on it in detail, given that it is not for XCB). The subsequent call to xcb_allow_events within the while-loop thaws (unfreezes) the pointer event processing. Passing the XCB_ALLOW_REPLAY_POINTER parameter replays the button events.
It's important to use xcb_poll_for_event within the loop, although I don't fully understand why.
I solved the mystery. Apparently XCB_GRAB_MODE_ASYNC does not do what I thought it would: The (correct) xcb_grab_pointer manual says that the pointer event processing continues normally. I thought that this would refer to the events being propagated to other clients, but this is not the case. The events are still only heard by my application. To propagate the events, they need to be replayed after receival:
xcb_generic_event_t *e;
xcb_generic_error_t *err;
xcb_connection_t *connection = xcb_connect(NULL, NULL);
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
xcb_void_cookie_t grab_cookie = xcb_grab_button_checked(connection, True, screen->root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY);
xcb_generic_error_t *error = xcb_request_check(connection, grab_cookie);
if (error != NULL)
xcb_disconnect(connection);
perror("could not subscribe to events on a window, bailing out");
exit(1);
free(error);
do {
xcb_allow_events(connection, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME);
e = xcb_poll_for_event(connection);
if(!e)
continue;
switch(e->response_type & EVENT_MASK)
case XCB_BUTTON_RELEASE:
case XCB_BUTTON_PRESS:
printf("Hello.n");
break;
default:
break;
free(e);
while(1);
xcb_ungrab_pointer(connection, XCB_TIME_CURRENT_TIME);
Before the do-while-loop, the pointer press and release for the index1 button are grabbed. The fifth argument has to be XCB_GRAB_MODE_SYNC so that the X server queues events until xcb_allow_events is called (the Xlib manual, man XGrabPointer, gives detailed information, though I wouldn't rely on it in detail, given that it is not for XCB). The subsequent call to xcb_allow_events within the while-loop thaws (unfreezes) the pointer event processing. Passing the XCB_ALLOW_REPLAY_POINTER parameter replays the button events.
It's important to use xcb_poll_for_event within the loop, although I don't fully understand why.
answered Oct 11 '17 at 13:50
PawkyPenguin
696110
696110
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f397339%2fxcb-asynchronous-pointer-grab-not-propagating-events%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password