Please, I'm begging for help! After over a month of finding a kernel
bug, building Xorg/mesa from scratch, rewriting code, to eliminate this
bug or secret, I've created a program to demonstrate.
I need the secret handshake or password to get any window manager,
except the great! twm to run this.
To build:
gcc -ansi -pedantic -Wall -g -o xmove xmove.c -lxcb
To run for bare xorg:
with no-wm either in xinitrc:
cd <where built>
./xmove
or with xterm:
exec $xterm -geometry 120X62+850+0 -name login
and from xterm:
cd <where built>
./xmove
with twm:
$twm &
exec $xterm -geometry 120X62+850+0 -name login
and from xterm:
cd <where built>
./xmove
from any OS with (arrrg) window manager: use console, not xinitrc
Don't say _NET_WM_MOVERESIZE because it doesn't work on every window
manager.
And on the 3 tested this 'grab' won't work. It has confines placed on
it from moving past edges or 'STRUT's where cursor gets separated from
drag point (mouse location).
PS freedesktop link from EWMH doesn't work, not that the managers
follow, and I don't expect a reply from stack exchange.
Steve
/*
* Move window demo
* Steven J Abner 2025
*/
#include <xcb/xcb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <inttypes.h>
#include <limits.h>
#include <poll.h>
/* gcc -ansi -pedantic -Wall -Wno-unknown-pragmas -g \
-o xmove xmove.c -lxcb */
typedef struct _PhxInterface PhxInterface;
typedef struct _PhxRectangle { int16_t x, y, w, h; } PhxRectangle;
xcb_connection_t *connection = NULL;
xcb_atom_t WM_PROTOCOLS;
xcb_atom_t WM_DELETE_WINDOW;
int16_t xroot, yroot;
struct _PhxInterface {
PhxRectangle mete_box;
xcb_window_t window;
} iface0 = { {0}, 0 };
#if (__STDC_VERSION__ <= 199901L)
#define RECTANGLE(a,b,c,d,e) \
a.x = b, a.y = c, a.w = d, a.h = e
#else
#define RECTANGLE(a,b,c,d,e) \
a = (PhxRectangle){ b, c, d, e }
#endif
static bool
event_keyboard(xcb_generic_event_t *nvt) {
xcb_key_press_event_t *kp = (xcb_key_press_event_t*)nvt;
xcb_client_message_event_t *message;
message = calloc(32, 1);
message->response_type = XCB_CLIENT_MESSAGE;
message->format = 32;
message->window = kp->event;
message->type = WM_PROTOCOLS;
message->data.data32[0] = WM_DELETE_WINDOW;
message->data.data32[1] = kp->time;
xcb_send_event(connection, false, message->window,
XCB_EVENT_MASK_NO_EVENT, (char*)message);
xcb_flush(connection);
return true;
}
static bool
event_mouse(xcb_generic_event_t *nvt) {
bool locus = ((nvt->response_type & (uint8_t)~0x80) == XCB_BUTTON_PRESS);
xcb_button_press_event_t *mouse
= (xcb_button_press_event_t*)nvt;
if (locus) {
xcb_grab_pointer_cookie_t c0;
xcb_grab_pointer_reply_t *r0;
xroot = mouse->root_x;
yroot = mouse->root_y;
c0 = xcb_grab_pointer(connection, 1, mouse->event,
XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE
| XCB_EVENT_MASK_POINTER_MOTION,
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
XCB_NONE, XCB_NONE, mouse->time);
r0 = xcb_grab_pointer_reply(connection, c0, NULL);
if ((r0 == NULL) || (r0->status != XCB_GRAB_STATUS_SUCCESS)) {
puts("grab failed");
return false;
}
} else {
xcb_ungrab_pointer(connection, mouse->time);
}
return true;
}
static bool
event_motion(xcb_generic_event_t *nvt) {
xcb_motion_notify_event_t *motion
= (xcb_motion_notify_event_t*)nvt;
if (!!(motion->state & XCB_BUTTON_MASK_1)) {
int32_t values[2];
xcb_query_pointer_cookie_t c0
= xcb_query_pointer(connection, iface0.window);
xcb_query_pointer_reply_t *r0
= xcb_query_pointer_reply(connection, c0, NULL);
xcb_flush(connection);
values[0] = (iface0.mete_box.x += (r0->root_x - xroot));
values[1] = (iface0.mete_box.y += (r0->root_y - yroot));
xroot = r0->root_x;
yroot = r0->root_y;
free(r0);
xcb_configure_window(connection, motion->event,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values);
xcb_flush(connection);
}
return true;
}
static int32_t
process_timers(void) {
return INT_MAX;
}
static bool
process_event(xcb_generic_event_t *nvt) {
switch (nvt->response_type & (uint8_t)~0x80) {
case XCB_KEY_PRESS: { /* response_type 2 */
event_keyboard(nvt);
break;
}
case XCB_KEY_RELEASE: { /* response_type 3 */
break;
}
case XCB_BUTTON_PRESS: /* response_type 4 */
case XCB_BUTTON_RELEASE: { /* response_type 5 */
event_mouse(nvt);
break;
}
case XCB_MOTION_NOTIFY: { /* response_type 6 */
event_motion(nvt);
break;
}
case XCB_ENTER_NOTIFY: /* response_type 7 */
case XCB_LEAVE_NOTIFY: { /* response_type 8 */
break;
}
case XCB_FOCUS_IN: { /* response_type 9 */
xcb_set_input_focus(connection,
XCB_INPUT_FOCUS_PARENT,
iface0.window, XCB_CURRENT_TIME);
break;
}
case XCB_FOCUS_OUT: { /* response_type 10 */
break;
}
case XCB_EXPOSE: { /* response_type 12 */
break;
}
case XCB_VISIBILITY_NOTIFY: { /* response_type 15 */
break;
}
case XCB_DESTROY_NOTIFY: { /* response_type 17 */
/* assume a kill, delete all windows (do their thing)
send false to exit loop */
free(nvt);
return false;
}
/* these 4 because of XCB_EVENT_MASK_STRUCTURE_NOTIFY */
case XCB_UNMAP_NOTIFY: { /* response_type 18 */
break;
}
case XCB_MAP_NOTIFY: { /* response_type 19 */
break;
}
case XCB_REPARENT_NOTIFY: { /* response_type 21 */
/* 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];
values[0] = iface0.mete_box.x;
values[1] = iface0.mete_box.y;
xcb_configure_window(connection, iface0.window,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values);
break;
}
case XCB_CONFIGURE_NOTIFY: { /* response_type 22 */
break;
}
case XCB_PROPERTY_NOTIFY: { /* response_type 28 */
case XCB_SELECTION_CLEAR: /* response_type 29 */
case XCB_SELECTION_REQUEST: /* response_type 30 */
case XCB_SELECTION_NOTIFY: /* response_type 31 */
break;
}
case XCB_CLIENT_MESSAGE: { /* response_type 33 */
xcb_client_message_event_t *cm
= (xcb_client_message_event_t*)nvt;
if (cm->type != WM_PROTOCOLS) goto report;
xcb_unmap_window(connection, iface0.window);
xcb_destroy_window(connection, iface0.window);
break;
}
default:
if (nvt->response_type == 0) {
xcb_generic_error_t *err = (xcb_generic_error_t*)nvt;
printf("error: %"PRIu8"\n", err->error_code);
break;
}
report:
/* Unknown event type, use to track coding problems */
printf("Unknown event: %"PRIu8"\n", nvt->response_type);
break;
} /* end switch(response_type) */
/* nvt no longer needed */
free(nvt);
/* critical! otherwise wont process anything done */
xcb_flush(connection);
return true;
}
static void
xcb_main(void) {
/* set all before through to Xserver */
xcb_flush(connection);
do {
int timeout;
xcb_generic_event_t *event;
while ((event = xcb_poll_for_event(connection)) != NULL)
/* _process_event() returns 'running' for main loop. */
if (process_event(event) == false) goto cleanup;
do {
/* _process_timers() runs any timers that are immediately pending,
and returns the number of milliseconds until the next timer
in the queue is ready.
_process_timers() returns INT_MAX if there are no timers. */
/* _process_timers() also removes from timeout its run time. */
timeout = process_timers();
if ((event = xcb_poll_for_queued_event(connection)) == NULL) break;
if (process_event(event) == false) goto cleanup;
} while (1);
if (timeout > 6) {
struct pollfd pfd[1];
pfd->fd = xcb_get_file_descriptor(connection);
pfd->events = POLLIN;
pfd->revents = POLLOUT;
poll(pfd, 1, timeout);
}
} while (1);
/* received XCB_DESTROY_NOTIFY */
cleanup:
return;
}
void
ui_window_name(xcb_window_t window) {
xcb_intern_atom_cookie_t cookie
= xcb_intern_atom(connection, 1, 7, "WM_NAME");
xcb_intern_atom_reply_t *reply
= xcb_intern_atom_reply(connection, cookie, NULL);
xcb_intern_atom_cookie_t cookie2
= xcb_intern_atom(connection, 0, 6, "STRING");
xcb_intern_atom_reply_t *reply2
= xcb_intern_atom_reply(connection, cookie2, NULL);
char title[16];
sprintf(title, "%d", window);
xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window,
reply->atom, reply2->atom, 8,
strlen(title), title);
free(reply);
free(reply2);
}
static void
_window_event_delete(xcb_connection_t *connection, xcb_window_t window) {
/* allow delete window so can quit application. Avoid ^C. */
xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window,
WM_PROTOCOLS, XCB_ATOM_ATOM, 32, 1,
&WM_DELETE_WINDOW);
}
static xcb_window_t
_window_create(PhxRectangle configure) {
xcb_screen_t *screen;
xcb_window_t window;
uint32_t mask;
uint32_t values[2];
if (connection == NULL) {
xcb_intern_atom_cookie_t c0, c1;
xcb_intern_atom_reply_t *r0, *r1;
connection = xcb_connect(NULL, NULL);
c0 = xcb_intern_atom(connection, 0, 12, "WM_PROTOCOLS");
c1 = xcb_intern_atom(connection, 0, 16, "WM_DELETE_WINDOW");
r0 = xcb_intern_atom_reply(connection, c0, NULL);
r1 = xcb_intern_atom_reply(connection, c1, NULL);
WM_PROTOCOLS = r0->atom; free((void*)r0);
WM_DELETE_WINDOW = r1->atom; free((void*)r1);
}
screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
/* Create the window */
window = xcb_generate_id(connection);
mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
values[0] = screen->white_pixel;
values[1] = 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 |
XCB_EVENT_MASK_VISIBILITY_CHANGE;
/* ignores x, y, border_width (virus) */
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 */
{
uint32_t value_list;
xcb_font_t font;
xcb_cursor_t cursor;
font = xcb_generate_id(connection);
xcb_open_font(connection, font, strlen ("cursor"), "cursor");
cursor = xcb_generate_id(connection);
xcb_create_glyph_cursor(connection, cursor, font, font,
132, 132 + 1,
0, 0, 0,
0, 0, 0);
value_list = cursor;
xcb_change_window_attributes(connection, window,
XCB_CW_CURSOR, &value_list);
}
_window_event_delete(connection, window);
return window;
}
xcb_window_t
ui_window_create(PhxRectangle configure) {
xcb_window_t window = _window_create(configure);
if (window == 0) return 0;
iface0.mete_box = configure;
iface0.window = window;
return window;
}
int
main(int argc, char *argv[]) {
xcb_window_t window;
/* window size and position */
PhxRectangle configure = { 800, 200, 300, 200 };
/* A 'topmost' decorated window */
window = ui_window_create(configure);
if (window == 0) exit(EXIT_FAILURE);
ui_window_name(window);
/* Map the window on the screen */
xcb_map_window(connection, window);
/* Run event loop */
xcb_main();
return EXIT_SUCCESS;
}