diff options
author | Jakob Kaivo <jkk@ung.org> | 2022-05-09 23:00:43 -0400 |
---|---|---|
committer | Jakob Kaivo <jkk@ung.org> | 2022-05-09 23:00:43 -0400 |
commit | 7f598bac4639258ec66cbb572a625f85cfa1c77e (patch) | |
tree | ddccc2bd04cd2f17e1060acac451204303803cc4 |
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 34 | ||||
-rw-r--r-- | xsnap.c | 178 |
3 files changed, 214 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..81bbe79 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +xsnap +*.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..032c251 --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +.POSIX: + +# This Makefile was generated by maje +# See https://src.kaivo.net/dev/maje/ for more information +# Do not edit this Makefile by hand + +CC=c99 +LD=$(CC) +CFLAGS=-Wall -Wextra -Wpedantic -Werror -g +LDFLAGS= +LDLIBS= -lX11 +SRCDIR=. +OBJDIR=. +BINDIR=$(OBJDIR) +LIBDIR=$(OBJDIR) +DESTDIR=/usr/local + +all: $(BINDIR)/xsnap + +clean: + rm -f $(BINDIR)/xsnap $(OBJDIR)/*.o + +install: $(BINDIR)/xsnap + mkdir -p $(DESTDIR)/bin + cp $(BINDIR)/xsnap $(DESTDIR)/bin + +$(BINDIR)/xsnap: $(OBJDIR)/xsnap.o +$(OBJDIR)/xsnap.o: $(SRCDIR)/xsnap.c + @mkdir -p $(@D) + $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)/xsnap.c + +$(BINDIR)/xsnap: + @mkdir -p $(@D) + $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/*.o $(LDLIBS) @@ -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; +} |