swim.git

swim.c

espurr
/* swim - window manager
 * Copyright (C) 2022-2023 ArcNyxx
 * see LICENCE file for licensing information */

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>

#include <X11/cursorfont.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xproto.h>

#include <X11/Xlib-xcb.h>

#include "draw.h"
#include "func.h"
#include "grab.h"
#include "mon.h"
#include "swim.h"
#include "util.h"

#define ATOM(name) XInternAtom(dpy, name, false)

static int (*xeorig)(Display *, XErrorEvent *);

static int xerror(Display *null, XErrorEvent *ev);

Display *dpy;
Atom atom[ATOM_LAST];

xcb_connection_t *c;
xcb_screen_t *screen;

static int
xerror(Display *null, XErrorEvent *ev)
{
	switch (ev->error_code) {
	case BadMatch:
		if (ev->request_code == X_ConfigureWindow ||
				ev->request_code == X_SetInputFocus)
			return 0;
		break;
	case BadValue:
		if (ev->request_code == X_KillClient)
			return 0;
		break;
	case BadDrawable:
		if (ev->request_code == X_CopyArea ||
				ev->request_code == X_PolyFillRectangle ||
				ev->request_code == X_PolySegment ||
				ev->request_code == X_PolyText8)
			return 0;
		break;
	case BadAccess:
		if (ev->request_code == X_ChangeWindowAttributes)
			die("swim: another window manager already running\n");
		if (ev->request_code == X_GrabButton ||
				ev->request_code == X_GrabKey)
			return 0;
		break;
	case BadWindow:   /* unable to check destroyed window access */
		return 0; /* ignored especially on unmapnotify */
	default:
		fprintf(stderr, "swim: fatal error: request (%d) error (%d)\n",
				ev->request_code, ev->error_code);
	}
	return xeorig(null, ev); /* may exit */
}

int
main(void)
{
	extern void (*evts[LASTEvent])(XEvent *);

	struct sigaction act = { .sa_handler = SIG_IGN,
			.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART };
	sigemptyset(&act.sa_mask); sigaction(SIGCHLD, &act, NULL);
	while (waitpid(-1, NULL, WNOHANG) > 0); /* clean inherited zombies */

	if ((dpy = XOpenDisplay(NULL)) == NULL)
		die("swim: unable to open display\n");
	xeorig = XSetErrorHandler(xerror);
	XSetWindowAttributes attrs = { .event_mask = ButtonPressMask |
			EnterWindowMask | LeaveWindowMask | PointerMotionMask |
			PropertyChangeMask | StructureNotifyMask |
			SubstructureNotifyMask | SubstructureRedirectMask,
			.cursor = XCreateFontCursor(dpy, XC_left_ptr) };
	XChangeWindowAttributes(dpy, ROOT, CWEventMask | CWCursor, &attrs);
	XSync(dpy, false);

	atom[CC_PROTOCOLS]    = ATOM("WM_PROTOCOLS");
	atom[CC_DELETE]       = ATOM("WM_DELETE_WINDOW");
	atom[CC_STATE]        = ATOM("WM_STATE");
	atom[CC_TAKE_FOCUS]   = ATOM("WM_TAKE_FOCUS");
	atom[NET_NAME]        = ATOM("_NET_WM_NAME");
	atom[NET_STATE]       = ATOM("_NET_WM_STATE");
	atom[NET_FULL]        = ATOM("_NET_WM_STATE_FULLSCREEN");
	atom[NET_TYPE]        = ATOM("_NET_WM_WINDOW_TYPE");
	atom[NET_DIALOG]      = ATOM("_NET_WM_WINDOW_TYPE_DIALOG");
	atom[NET_ACTIVE]      = ATOM("_NET_ACTIVE");
	atom[NET_CLIENT_LIST] = ATOM("_NET_CLIENT_LIST");

	Atom chkatom = ATOM("_NET_SUPPORTING_WM_CHECK");
	Window chkwin = XCreateSimpleWindow(dpy, ROOT, 0, 0, 1, 1, 0, 0, 0);
	XChangeProperty(dpy, chkwin, chkatom, XA_WINDOW, 32,
			PropModeReplace, (void *)&chkwin, 1);
	XChangeProperty(dpy, ROOT, chkatom, XA_WINDOW, 32,
			PropModeReplace, (void *)&chkwin, 1);
	XChangeProperty(dpy, chkwin, atom[NET_NAME], ATOM("UTF8_STRING"), 8,
			PropModeReplace, (const void *)"swim", 4);
	XChangeProperty(dpy, ROOT, ATOM("_NET_SUPPORTED"), XA_ATOM, 32,
			PropModeReplace, (void *)(&atom[NET_NAME]), 7);
	XDeleteProperty(dpy, ROOT, atom[NET_CLIENT_LIST]);

	c = XGetXCBConnection(dpy);
	const xcb_setup_t *setup  = xcb_get_setup (c);
    	screen = (xcb_setup_roots_iterator (setup)).data;

	extern mon_t *mons, *sel;

	XEvent ev;
	grabkeys(); drawinit();


	extern uint32_t visual_fmt;

	chmon(c, screen, visual_fmt, &mons);
	sel = mons;
	while (!XNextEvent(dpy, &ev)) {
		if (ev.type == ConfigureNotify &&
				ev.xconfigure.window == ROOT) {
			chmon(c, screen, visual_fmt, &mons);
			sel = mons;
		}
		if (evts[ev.type] != NULL)
			evts[ev.type](&ev);
	}
}