master ohmu/wmutils / src / opt / xmmv.c
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}