summaryrefslogtreecommitdiff
path: root/xsnap.c
diff options
context:
space:
mode:
authorJakob Kaivo <jkk@ung.org>2022-05-09 23:00:43 -0400
committerJakob Kaivo <jkk@ung.org>2022-05-09 23:00:43 -0400
commit7f598bac4639258ec66cbb572a625f85cfa1c77e (patch)
treeddccc2bd04cd2f17e1060acac451204303803cc4 /xsnap.c
initial commitHEADxsnap
Diffstat (limited to 'xsnap.c')
-rw-r--r--xsnap.c178
1 files changed, 178 insertions, 0 deletions
diff --git a/xsnap.c b/xsnap.c
new file mode 100644
index 0000000..df5d55c
--- /dev/null
+++ b/xsnap.c
@@ -0,0 +1,178 @@
+#define _POSIX_C_SOURCE 200809L
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <X11/Xlib.h>
+
+/* MAJE_LDLIB=-lX11 */
+
+#define WM_STATE_FORMAT 32
+
+static Bool is_normal(Display *dpy, Window win)
+{
+ static Atom state = None;
+ if (state == None) {
+ state = XInternAtom(dpy, "WM_STATE", True);
+ if (state == None) {
+ return False;
+ }
+ }
+
+ Atom type = AnyPropertyType;
+ int format = WM_STATE_FORMAT;
+ unsigned long nitems = 0;
+ unsigned long bytes = 0;
+ unsigned char *prop = NULL;
+
+ int r = XGetWindowProperty(dpy,
+ win,
+ state,
+ 0,
+ 0,
+ False,
+ type,
+ &type,
+ &format,
+ &nitems,
+ &bytes,
+ &prop);
+
+ if (r == Success && prop != NULL) {
+ XFree(prop);
+ return True;
+ }
+
+ return False;
+}
+
+static Window find_normal_parent(Display *dpy, Window win)
+{
+ if (win == PointerRoot || win == None || is_normal(dpy, win)) {
+ return win;
+ }
+
+ Window root = win, parent = win, *children = NULL;
+ unsigned int nchildren = 0;
+ if (!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) {
+ return None;
+ }
+
+ if (parent == win || is_normal(dpy, parent)) {
+ return parent;
+ }
+
+ return find_normal_parent(dpy, win);
+}
+
+static int xsnap_error(Display *dpy, XErrorEvent *e)
+{
+ char buf[BUFSIZ];
+ XGetErrorText(dpy, e->error_code, buf, sizeof(buf));
+ fprintf(stderr, "xsnap: %s\n", buf);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ enum { NONE, LEFT, RIGHT, UP, DOWN } dir = NONE;
+
+ int c = 0;
+ while ((c = getopt(argc, argv, "lrud")) != -1) {
+ switch (c) {
+ case 'l':
+ dir = LEFT;
+ break;
+
+ case 'r':
+ dir = RIGHT;
+ break;
+
+ case 'u':
+ dir = UP;
+ break;
+
+ case 'd':
+ dir = DOWN;
+ break;
+
+ default:
+ return 1;
+ }
+ }
+
+ if (dir == NONE) {
+ fprintf(stderr, "xsnap: missing direction\n");
+ return 1;
+ }
+
+ /* TODO: if operand, use that, otherwise find focused */
+
+ Display *dpy = XOpenDisplay(NULL);
+ XSetErrorHandler(xsnap_error);
+
+ Window root = XDefaultRootWindow(dpy);
+
+ Window focused = root;
+ int revert = RevertToNone;
+ XGetInputFocus(dpy, &focused, &revert);
+ focused = find_normal_parent(dpy, focused);
+
+ XWindowAttributes rootattr = { 0 };
+ XGetWindowAttributes(dpy, root, &rootattr);
+
+ XWindowAttributes attributes = { 0 };
+ XGetWindowAttributes(dpy, focused, &attributes);
+
+ if (!attributes.override_redirect) {
+ fprintf(stderr, "can't override redirect\n");
+ exit(1);
+ }
+
+ int x = 0;
+ int y = 0;
+ unsigned w = 0;
+ unsigned h = 0;
+
+ switch (dir) {
+ case LEFT:
+ x = 0;
+ y = 0;
+ w = rootattr.width / 2;
+ h = rootattr.height;
+ break;
+
+ case RIGHT:
+ x = rootattr.width / 2;
+ y = 0;
+ w = rootattr.width / 2;
+ h = rootattr.height;
+ break;
+
+ case UP:
+ x = 0;
+ y = 0;
+ w = rootattr.width;
+ h = rootattr.height / 2;
+ break;
+
+ case DOWN:
+ x = 0;
+ y = rootattr.height / 2;
+ w = rootattr.width;
+ h = rootattr.height / 2;
+ break;
+
+ default:
+ fprintf(stderr, "somehow missing direction\n");
+ return 1;
+ break;
+ }
+
+ int r = XMoveResizeWindow(dpy, focused, x, y, w ? w : 1, h ? h : 1);
+ if (r != 0) {
+ XErrorEvent e = { .error_code = r };
+ xsnap_error(dpy, &e);
+ }
+
+ return 0;
+}