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#define MAX(a, b) (a > b ? a : b)
11
12static xcb_connection_t *conn;
13static xcb_screen_t *scr;
14
15static void usage(char *);
16static xcb_window_t get_focuswin(void);
17static void cleanup(void);
18
19static void
20cleanup(void)
21{
22 kill_xcb(&conn);
23}
24
25static void
26usage(char *name)
27{
28 fprintf(stderr, "usage: %s <wid>\n", name);
29 exit(1);
30}
31
32static xcb_window_t
33get_focuswin(void) {
34 xcb_window_t w = 0;
35
36 xcb_get_input_focus_cookie_t c;
37 xcb_get_input_focus_reply_t *r;
38
39 c = xcb_get_input_focus(conn);
40 r = xcb_get_input_focus_reply(conn, c, NULL);
41
42 if (r == NULL)
43 errx(1, "failed to get focused window");
44
45 w = r->focus;
46 free(r);
47 return w;
48}
49
50static void
51mresize(xcb_window_t win) {
52 uint32_t values[3];
53 xcb_get_geometry_reply_t *geom;
54 xcb_query_pointer_reply_t *ptr;
55 xcb_generic_event_t *ev = NULL;
56 int orig_width, orig_height;
57
58 geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
59 xcb_warp_pointer(conn, XCB_NONE, win, 0, 0, 0, 0,
60 geom->width, geom->height);
61
62 if (!geom)
63 errx(1, "could not get window size");
64
65 orig_width = geom->width;
66 orig_height = geom->height;
67
68 if (!scr->root)
69 return;
70
71 xcb_grab_pointer(conn, 0, scr->root,
72 XCB_EVENT_MASK_BUTTON_RELEASE
73 | XCB_EVENT_MASK_BUTTON_PRESS,
74 XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
75 scr->root, XCB_NONE, XCB_CURRENT_TIME);
76
77 xcb_flush(conn);
78
79
80 for (;;) {
81 ev = xcb_poll_for_event(conn);
82
83 if (geom->width != orig_width || geom->height != orig_height)
84 if (ev != NULL) {
85 if (ev->response_type == XCB_MOTION_NOTIFY)
86 break;
87 exit(0);
88 }
89
90 geom = xcb_get_geometry_reply(conn,
91 xcb_get_geometry(conn, win), NULL);
92 if (!geom)
93 errx(1, "could not get window size");
94
95
96 ptr = xcb_query_pointer_reply(conn,
97 xcb_query_pointer(conn, scr->root), 0);
98
99 if (!ptr)
100 errx(1, "could not get pointer location");
101
102 values[0] = MAX(1, ptr->root_x - geom->x - 2 * geom->border_width);
103 values[1] = MAX(1, ptr->root_y - geom->y - 2 * geom->border_width);
104
105
106 if (values[0] >= 0 && values[1] >= 0)
107 xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_WIDTH
108 | XCB_CONFIG_WINDOW_HEIGHT, values);
109 xcb_flush(conn);
110 }
111
112 xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
113}
114
115int
116main(int argc, char **argv)
117{
118 xcb_window_t win;
119
120 if (argc > 2)
121 usage(argv[0]);
122
123 init_xcb(&conn);
124 get_screen(conn, &scr);
125 atexit(cleanup);
126
127 if (argc == 2)
128 win = strtoul(argv[1], NULL, 16);
129 else
130 win = get_focuswin();
131
132 mresize(win);
133
134 return 0;
135}