ohmu
·
2026-07-25
1/* See LICENSE file for copyright and license details. */
2#include <xcb/xcb.h>
3#include <stdlib.h>
4#include <stdio.h>
5#include <err.h>
6
7#include "util.h"
8
9#define CLEANMASK(m) ((m & ~0x80))
10
11static xcb_connection_t *conn;
12static xcb_screen_t *scr;
13
14static void usage(char *);
15static xcb_window_t get_focuswin(void);
16static void cleanup(void);
17
18static void
19cleanup(void)
20{
21 kill_xcb(&conn);
22}
23
24static void
25usage(char *name)
26{
27 fprintf(stderr, "usage: %s <wid>\n", name);
28 exit(1);
29}
30
31static xcb_window_t
32get_focuswin(void) {
33 xcb_window_t w = 0;
34
35 xcb_get_input_focus_cookie_t c;
36 xcb_get_input_focus_reply_t *r;
37
38 c = xcb_get_input_focus(conn);
39 r = xcb_get_input_focus_reply(conn, c, NULL);
40
41 if (r == NULL)
42 errx(1, "failed to get focused window");
43
44 w = r->focus;
45 free(r);
46 return w;
47}
48
49static void
50mmove(xcb_window_t win) {
51 uint32_t values[3];
52 xcb_get_geometry_reply_t *geom;
53 xcb_query_pointer_reply_t *ptr;
54 xcb_generic_event_t *ev = NULL;
55 int orig_x, orig_y;
56
57 geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
58 xcb_warp_pointer(conn, XCB_NONE, win, 0, 0, 0, 0,
59 geom->width/2, geom->height/2);
60
61 if (!geom)
62 errx(1, "could not get window size");
63
64 orig_x = geom->x;
65 orig_y = geom->y;
66
67 if (!scr->root)
68 return;
69
70 xcb_grab_pointer(conn, 0, scr->root,
71 XCB_EVENT_MASK_BUTTON_RELEASE
72 | XCB_EVENT_MASK_BUTTON_PRESS,
73 XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
74 scr->root, XCB_NONE, XCB_CURRENT_TIME);
75
76 xcb_flush(conn);
77
78
79 for (;;) {
80 ev = xcb_poll_for_event(conn);
81
82 if (geom->x != orig_x || geom->y != orig_y)
83 if (ev != NULL) {
84 if (ev->response_type == XCB_MOTION_NOTIFY)
85 break;
86 exit(0);
87 }
88
89 geom = xcb_get_geometry_reply(conn,
90 xcb_get_geometry(conn, win), NULL);
91 if (!geom)
92 errx(1, "could not get window size");
93
94
95 ptr = xcb_query_pointer_reply(conn,
96 xcb_query_pointer(conn, scr->root), 0);
97
98 if (!ptr)
99 errx(1, "could not get pointer location");
100
101 values[0] = ptr->root_x + geom->width/2;
102 values[1] = ptr->root_y + geom->height/2;
103
104 values[0] = (ptr->root_x + geom->width / 2
105 > scr->width_in_pixels
106 - (geom->border_width*2))
107 ? scr->width_in_pixels - geom->width
108 - (geom->border_width*2)
109 : ptr->root_x - geom->width / 2;
110 values[1] = (ptr->root_y + geom->height / 2
111 > scr->height_in_pixels
112 - (geom->border_width*2))
113 ? (scr->height_in_pixels - geom->height
114 - (geom->border_width*2))
115 : ptr->root_y - geom->height / 2;
116
117 if (ptr->root_x < geom->width/2)
118 values[0] = 0;
119 if (ptr->root_y < geom->height/2)
120 values[1] = 0;
121
122 xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_X
123 | XCB_CONFIG_WINDOW_Y, values);
124 xcb_flush(conn);
125 }
126
127 xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
128}
129
130int
131main(int argc, char **argv)
132{
133 xcb_window_t win;
134
135 if (argc > 2)
136 usage(argv[0]);
137
138 init_xcb(&conn);
139 get_screen(conn, &scr);
140 atexit(cleanup);
141
142 if (argc == 2)
143 win = strtoul(argv[1], NULL, 16);
144 else
145 win = get_focuswin();
146
147 mmove(win);
148
149 return 0;
150}