On Wed, Jul 10 2024 at 02:10:15 PM +0000, Julian Bradfield
<jcb+...@julianbradfield.org> wrote:
You haven't given anything like enough information. However, what I
suspect this means is that some other client, such as a window
manager, has a passive grab on the button, so when you pressed the
button, the other client grabbed it (causing a LeaveNotify to your
client), and then released the grab (causing the EnterNotify) and
passed the ButtonPress on to your client.
I'll buy the window manager! Just to be sure though, could you please
try attached. It's a quickly butchered base of what I have. When over
window, just use button 2.
Created/run by:
gcc -g basic.c -lxcb && ./a.out
And thank you for a response and that bit of help!
And if window manager, I guess nothing to be done but let it ride :(
Steve
#include <sys/types.h>
#include <xcb/xcb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <inttypes.h>
typedef struct { int16_t x, y, w, h; } PhxRectangle;
#define DEBUG_EVENTS 1
static char *
_xkey_names(xcb_keysym_t sym) {
(void)sym;
return "XK_Return";
}
static xcb_keysym_t
_xcb_keysym_for(xcb_keycode_t keycode, uint16_t modifiers) {
(void)keycode;
(void)modifiers;
return 0x0ff0d;
}
static void
xcb_main(xcb_connection_t *connection, xcb_window_t window) {
#if DEBUG_EVENTS
puts("XCB_PROP_MODE_REPLACE");
#endif
/* code to allow delete window instead of quit */
xcb_intern_atom_cookie_t cookie
= xcb_intern_atom(connection, 1, 12, "WM_PROTOCOLS");
xcb_intern_atom_reply_t *reply
= xcb_intern_atom_reply(connection, cookie, 0);
xcb_intern_atom_cookie_t cookie2
= xcb_intern_atom(connection, 0, 16, "WM_DELETE_WINDOW");
/* reply2 needs retension for XCB_CLIENT_MESSAGE */
xcb_intern_atom_reply_t* reply2
= xcb_intern_atom_reply(connection, cookie2, 0);
xcb_change_property(connection, XCB_PROP_MODE_REPLACE,
window,
(*reply).atom, XCB_ATOM_ATOM, 32, 1, &(*reply2).atom);
/* set all before through to Xserver */
xcb_flush(connection);
/* setting of window per user's request */
_Bool once = true;
/* set to false after all windows closed */
_Bool run_loop = true;
xcb_generic_event_t *event;
while ( run_loop && (event = xcb_wait_for_event(connection)) ) {
switch (event->response_type & ~0x80) {
case XCB_KEY_PRESS: { /* response_type 2 */
xcb_key_press_event_t *kp = (xcb_key_press_event_t*)event;
xcb_keysym_t keyval = _xcb_keysym_for(kp->detail, kp->state);
#if DEBUG_EVENTS
printf("window %"PRIu32" KEY_PRESS"
" code %"PRIu8" modifers %"PRIu16""
" keyval %"PRIx32" key_name %s\n",
kp->event, kp->detail, kp->state, keyval, _xkey_names(keyval));
#endif
break;
}
case XCB_KEY_RELEASE: { /* response_type 3 */
xcb_key_release_event_t *kr = (xcb_key_release_event_t*)event;
xcb_keysym_t keyval = _xcb_keysym_for(kr->detail, kr->state);
#if DEBUG_EVENTS
printf("window %"PRIu32" KEY_RELEASE"
" code %"PRIu8" modifers %"PRIu16""
" keyval %"PRIx32" key_name %s\n",
kr->event, kr->detail, kr->state, keyval, _xkey_names(keyval));
#endif
break;
}
case XCB_BUTTON_PRESS: { /* response_type 4 */
xcb_button_press_event_t *bp = (xcb_button_press_event_t*)event;
#if DEBUG_EVENTS
switch (bp->detail) {
case 4:
printf("window %"PRIu32", BUTTON_PRESS Wheel Scroll up"
" modifier %"PRIu16" (%"PRIi16",%"PRIi16")\n",
bp->event, bp->state, bp->event_x, bp->event_y);
break;
case 5:
printf("window %"PRIu32", BUTTON_PRESS Wheel Scroll down"
" modifier %"PRIu16" (%"PRIi16",%"PRIi16")\n",
bp->event, bp->state, bp->event_x, bp->event_y);
break;
case 6:
printf("window %"PRIu32", BUTTON_PRESS Wheel Scroll left"
" modifier %"PRIu16" (%"PRIi16",%"PRIi16")\n",
bp->event, bp->state, bp->event_x, bp->event_y);
break;
case 7:
printf("window %"PRIu32", BUTTON_PRESS Wheel Scroll right"
" modifier %"PRIu16" (%"PRIi16",%"PRIi16")\n",
bp->event, bp->state, bp->event_x, bp->event_y);
break;
default:
printf("window %"PRIu32", BUTTON_PRESS Button %"PRIu8""
" modifier %"PRIu16" (%"PRIi16",%"PRIi16")\n",
bp->event, bp->detail, bp->state, bp->event_x, bp->event_y);
break;
}
#endif
break;
}
case XCB_BUTTON_RELEASE: { /* response_type 5 */
xcb_button_release_event_t *br = (xcb_button_release_event_t*)event;
#if DEBUG_EVENTS
printf("window %"PRIu32", BUTTON_RELEASE Button %"PRIu8""
" modifier %"PRIu16" (%"PRIi16",%"PRIi16")\n",
br->event, br->detail, br->state, br->event_x, br->event_y);
#endif
break;
}
case XCB_MOTION_NOTIFY: { /* response_type 6 */
xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t*)event;
#if DEBUG_EVENTS
// printf("window %"PRIu32", MOTION_NOTIFY (%"PRIi16",%"PRIi16")\n",
// motion->event, motion->event_x, motion->event_y);
#endif
break;
}
case XCB_ENTER_NOTIFY: { /* response_type 7 */
xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t*)event;
#if DEBUG_EVENTS
printf("window %"PRIu32", ENTER_NOTIFY (%"PRIi16",%"PRIi16")\n",
enter->event, enter->event_x, enter->event_y);
#endif
break;
}
case XCB_LEAVE_NOTIFY: { /* response_type 8 */
xcb_leave_notify_event_t *leave = (xcb_leave_notify_event_t*)event;
#if DEBUG_EVENTS
printf("window %"PRIu32", LEAVE_NOTIFY (%"PRIi16",%"PRIi16")\n",
leave->event, leave->event_x, leave->event_y);
#endif
break;
}
case XCB_FOCUS_IN: { /* response_type 9 */
xcb_focus_in_event_t *fi = (xcb_focus_in_event_t*)event;
#if DEBUG_EVENTS
printf("window %"PRIu32" FOCUS_IN\n", fi->event);
#endif
break;
}
case XCB_FOCUS_OUT: { /* response_type 10 */
xcb_focus_out_event_t *fo = (xcb_focus_out_event_t*)event;
#if DEBUG_EVENTS
printf("window %"PRIu32" FOCUS_OUT\n", fo->event);
#endif
break;
}
case XCB_EXPOSE: { /* response_type 12 */
xcb_expose_event_t *expose = (xcb_expose_event_t*)event;
// if (expose->count != 0) break;
#if DEBUG_EVENTS
printf("window %"PRIu32" EXPOSE. Region"
" (%"PRIu16",%"PRIu16",%"PRIu16",%"PRIu16")\n",
expose->window, expose->x, expose->y,
expose->width, expose->height);
#endif
break;
}
/* these 4 because of XCB_EVENT_MASK_STRUCTURE_NOTIFY */
case XCB_UNMAP_NOTIFY: { /* response_type 18 */
#if DEBUG_EVENTS
/* iconify for one */
puts("XCB_UNMAP_NOTIFY");
#endif
break;
}
case XCB_MAP_NOTIFY: { /* response_type 19 */
#if DEBUG_EVENTS
puts("XCB_MAP_NOTIFY");
#endif
/* occurs: start up, deiconify */
break;
}
case XCB_REPARENT_NOTIFY: { /* response_type 21 */
#if DEBUG_EVENTS
puts("XCB_REPARENT_NOTIFY");
#endif
// if (once) {
/* position after map, to design user requested of window
* set once and when window manager asks to reparent
* dont need during icon/deiconify
* doesnt stop WM configures, but will be sent after map notify */
// uint32_t values[2] = {
// master_iface->mete_box.x,
// master_iface->mete_box.y
// };
// xcb_configure_window(connection, master_iface->window,
// XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values);
// once = false;
// }
break;
}
case XCB_CONFIGURE_NOTIFY: { /* response_type 22 */
xcb_configure_notify_event_t *configure;
configure = (xcb_configure_notify_event_t*)event;
#if DEBUG_EVENTS
printf("window %"PRIu32" CONFIGURE_NOTIFY."
" (%"PRIu16",%"PRIu16",%"PRIu16",%"PRIu16")\n",
configure->window, configure->x, configure->y,
configure->width, configure->height);
#endif
break;
}
/* added to delete window, inform deletion */
/* set up as 1 window, so quits also */
case XCB_CLIENT_MESSAGE: { /* response_type 33 */
xcb_client_message_event_t *cm = (xcb_client_message_event_t*)event;
#if DEBUG_EVENTS
puts("XCB_CLIENT_MESSAGE");
#endif
/* does quit ince single window (for now) */
if (cm->data.data32[0] == (*reply2).atom) {
printf(" Kill client %d\n", cm->window);
xcb_unmap_window(connection, cm->window);
xcb_flush(connection);
xcb_destroy_window(connection, cm->window);
run_loop = false;
}
break;
}
default:
/* Unknown event type, ignore it */
printf("Unknown event: %"PRIu8"\n", event->response_type);
break;
} /* end switch(response_type) */
/* event no longer needed */
free(event);
/* critical! otherwise wont process anything done */
xcb_flush(connection);
}
/* clean up any needed variables used for loop */
}
static xcb_window_t
ui_create_window(xcb_connection_t *connection, PhxRectangle configure) {
/* Get the first screen */
xcb_screen_t *screen;
screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
/* Create the window */
xcb_window_t window = xcb_generate_id(connection);
uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
uint32_t values[2] = { screen->white_pixel,
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION |
XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE |
XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY };
/* ignores x, y, border_width, x,y after mapping */
/* seems WM will center the width/height in what it defines
as display area (less WM border decoration). Border is never used? */
/* A use of 0,0 can be used to determine WM decorations */
/* A poormans screen width and height can be gleened */
/* not sure why double expose, one of full content, one of 9 pixels
at the bottom width of the window */
xcb_create_window(connection,
screen->root_depth, /* depth */
window, /* generated id */
screen->root, /* parent window */
configure.x, /* x, y */
configure.y,
configure.w, /* width, height */
configure.h,
0, /* border_width */
XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */
screen->root_visual, /* visual */
mask, values); /* masks */
return window;
}
int
main(int argc, char *argv[]) {
xcb_connection_t *connection = xcb_connect(NULL, NULL);
if (xcb_connection_has_error(connection)) {
fprintf(stderr, "Could not connect to X11 server");
exit(EXIT_FAILURE);
}
PhxRectangle configure = { 100, 200, 800, 200 };
/* A 'topmost' decorated window */
xcb_window_t window = ui_create_window(connection, configure);
if (window == 0) exit(EXIT_FAILURE);
/* Map the window on the screen */
xcb_map_window(connection, window);
xcb_main(connection, window);
/* Disconnect from X server */
xcb_disconnect(connection);
return EXIT_SUCCESS;
}