swim.git
swim.c
/* 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);
}
}