swim.git

func.c

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

#include <signal.h>
#include <stdbool.h>
#include <unistd.h>

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

#include "bar.h"
#include "func.h"
#include "grab.h"
#include "swim.h"
#include "tile.h"
#include "util.h"

extern mon_t *sel;
extern XColor xclrs[CLR_LST];

void
focus(cli_t *cli)
{
	if (cli == NULL || !VIS(cli))
		if ((cli = next(sel->cli)) == NULL)
			for (cli = sel->cli; cli != NULL && !VIS(cli);
					cli = cli->next);
	if (sel->sel != NULL && sel->sel != cli)
		unfocus(sel->sel, false);

	if (cli != NULL) {
		if (cli->mon != sel)
			sel = cli->mon;
		if (cli->urg)
			seturg(cli, false);

		grabbuttons(cli, true);
		XSetWindowBorder(dpy, cli->win, xclrs[CLR_SEL].pixel);
	}

	XSetInputFocus(dpy, cli != NULL && !cli->nfc ? cli->win : ROOT,
			RevertToPointerRoot, CurrentTime);
	XChangeProperty(dpy, ROOT, atom[NET_ACTIVE], XA_WINDOW, 32,
			PropModeReplace, (void *)(cli != NULL && !cli->nfc ?
			(Window *)&cli->win : &(Window){ 0 }), 1);
	if (cli != NULL)
		sendevent(cli, atom[CC_TAKE_FOCUS]);
	sel->sel = cli;
	drawbars();
}

void
unfocus(cli_t *cli, bool fcs)
{
	if (cli != NULL) {
		grabbuttons(cli, false);
		XSetWindowBorder(dpy, cli->win, xclrs[CLR_NRM].pixel);
		if (fcs) {
			XSetInputFocus(dpy, ROOT, RevertToPointerRoot,
					CurrentTime);
			XDeleteProperty(dpy, ROOT, atom[NET_ACTIVE]);
		}
	}
}

bool
sendevent(cli_t *cli, Atom prop)
{
	int num; Atom *props; bool supp = false;
	if (XGetWMProtocols(dpy, cli->win, &props, &num)) {
		while (!supp && --num)
			supp = props[num] == prop;
		XFree(props);
	}
	if (supp) {
		XEvent ev = { .type = ClientMessage };
		ev.xclient = (XClientMessageEvent){ .format = 32, .window =
				cli->win, .message_type = atom[CC_PROTOCOLS],
				.data.l[0] = prop, .data.l[1] = CurrentTime };
		XSendEvent(dpy, cli->win, false, NoEventMask, &ev);
	}
	return supp;
}

void
seturg(cli_t *cli, bool urg)
{
	XWMHints *wmh;
	if ((wmh = XGetWMHints(dpy, cli->win)) != NULL) {
		wmh->flags = (cli->urg = urg) ? wmh->flags | XUrgencyHint :
				wmh->flags & ~XUrgencyHint;
		XSetWMHints(dpy, cli->win, wmh);
		XFree(wmh);
	}
}

void
spawn(long arg)
{
	if (fork() == 0) {
		close(ConnectionNumber(dpy)); setsid();
		struct sigaction act = { .sa_handler = SIG_DFL };
		sigemptyset(&act.sa_mask); sigaction(SIGCHLD, &act, NULL);

		execvp(((char *const *)arg)[0], (char *const *)arg);
		die("swim: unable to run %s: ", ((char *const *)arg)[0]);
	}
}