commit 5cca9b2

0uppy  ·  2026-03-13 15:38:14 +0000 UTC
parent 4af3e85
slgro 1.0 - Source directory
3 files changed,  +758, -0
+57, -0
 1@@ -0,0 +1,57 @@
 2+#ifndef CONFIG_H
 3+#define CONFIG_H
 4+
 5+#include <xkbcommon/xkbcommon-keysyms.h>
 6+
 7+
 8+#include "include/types.h"
 9+#include "include/slgro.h"
10+
11+static const struct config cfg = {
12+	.motion_throttle_hz = 85,
13+	.border_col_active = 0xffed953e,
14+	.border_col_normal = 0xff444444,
15+	.border_width = 1,
16+	.gaps = 0,
17+};
18+
19+static const char* termcmd[] = { "havoc", NULL };
20+static struct bind binds[] = {
21+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_Return, { .v = termcmd }, spawn },
22+	{ SWC_BINDING_KEY,    MOD4|SHFT,   XKB_KEY_q,      { .v = NULL },    quit },
23+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_Tab,    { .v = NULL },    focus_next },
24+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_f,      { .v = NULL },    fullscreen },
25+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_q,      { .v = NULL },    kill_sel },
26+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_Right,  { .i =  100 },     kb_move_x },
27+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_Left,   { .i = -100 },     kb_move_x },
28+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_Down,   { .i =  100 },     kb_move_y },
29+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_Up,     { .i = -100 },     kb_move_y },
30+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_space,  { .v = NULL },    center_window },
31+	{ SWC_BINDING_KEY,    MOD4|SHFT,   XKB_KEY_Right,  { .i =  50 },     kb_resize_width },
32+	{ SWC_BINDING_KEY,    MOD4|SHFT,   XKB_KEY_Left,   { .i = -50 },     kb_resize_width },
33+	{ SWC_BINDING_KEY,    MOD4|SHFT,   XKB_KEY_Down,   { .i =  50 },     kb_resize_height },
34+	{ SWC_BINDING_KEY,    MOD4|SHFT,   XKB_KEY_Up,     { .i = -50 },     kb_resize_height },
35+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_h,      { .v = NULL },    snap_left_half },
36+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_l,      { .v = NULL },    snap_right_half },
37+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_1,      { .ui = 1 },      workspace_goto },
38+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_2,      { .ui = 2 },      workspace_goto },
39+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_3,      { .ui = 3 },      workspace_goto },
40+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_4,      { .ui = 4 },      workspace_goto },
41+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_5,      { .ui = 5 },      workspace_goto },
42+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_6,      { .ui = 6 },      workspace_goto },
43+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_7,      { .ui = 7 },      workspace_goto },
44+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_8,      { .ui = 8 },      workspace_goto },
45+	{ SWC_BINDING_KEY,    MOD4,        XKB_KEY_9,      { .ui = 9 },      workspace_goto },
46+	{ SWC_BINDING_KEY,    MOD4|SHFT,   XKB_KEY_1,      { .ui = 1 },      workspace_moveto },
47+	{ SWC_BINDING_KEY,    MOD4|SHFT,   XKB_KEY_2,      { .ui = 2 },      workspace_moveto },
48+	{ SWC_BINDING_KEY,    MOD4|SHFT,   XKB_KEY_3,      { .ui = 3 },      workspace_moveto },
49+	{ SWC_BINDING_KEY,    MOD4|SHFT,   XKB_KEY_4,      { .ui = 4 },      workspace_moveto },
50+	{ SWC_BINDING_KEY,    MOD4|SHFT,   XKB_KEY_5,      { .ui = 5 },      workspace_moveto },
51+	{ SWC_BINDING_KEY,    MOD4|SHFT,   XKB_KEY_6,      { .ui = 6 },      workspace_moveto },
52+	{ SWC_BINDING_KEY,    MOD4|SHFT,   XKB_KEY_7,      { .ui = 7 },      workspace_moveto },
53+	{ SWC_BINDING_KEY,    MOD4|SHFT,   XKB_KEY_8,      { .ui = 8 },      workspace_moveto },
54+	{ SWC_BINDING_KEY,    MOD4|SHFT,   XKB_KEY_9,      { .ui = 9 },      workspace_moveto },
55+
56+};
57+
58+#endif /* CONFIG_H */
+657, -0
  1@@ -0,0 +1,657 @@
  2+#include <asm-generic/errno.h>
  3+#include <signal.h>
  4+#include <stdio.h>
  5+#include <stdlib.h>
  6+#include <unistd.h>
  7+
  8+#include <swc.h>
  9+#include <wayland-server.h>
 10+#include <wayland-util.h>
 11+#include <xkbcommon/xkbcommon-keysyms.h>
 12+
 13+#include "config.h"
 14+#include "include/types.h"
 15+#include "include/util.h"
 16+#include "include/slgro.h"
 17+
 18+static void focus(struct client* c);
 19+static struct client* first_client(struct screen* s);
 20+static bool is_ws_client(const struct client* c, const struct screen* s);
 21+static void on_screen_destroy(void* data);
 22+static void on_win_destroy(void* data);
 23+static void on_win_entered(void* data);
 24+static void setup(void);
 25+static void setup_binds(void);
 26+static void sync_window_visibility(void);
 27+
 28+struct wm wm;
 29+const struct swc_manager manager = {
 30+	.new_screen = new_screen, .new_window = new_window, .new_device = new_device,
 31+};
 32+struct swc_window_handler window_handler = {
 33+	.destroy = on_win_destroy, .entered = on_win_entered,
 34+};
 35+struct swc_screen_handler screen_handler = {
 36+	.destroy = on_screen_destroy,
 37+};
 38+
 39+static void focus(struct client* c)
 40+{
 41+	if (wm.sel_client)
 42+		swc_window_set_border(
 43+			wm.sel_client->win,
 44+			cfg.border_col_normal, cfg.border_width,
 45+			0, 0
 46+		);
 47+
 48+	if (c)
 49+		swc_window_set_border(
 50+			c->win,
 51+			cfg.border_col_active, cfg.border_width,
 52+			0, 0
 53+		);
 54+
 55+	swc_window_focus(c ? c->win : NULL);
 56+	wm.sel_client = c;
 57+}
 58+
 59+static struct client* first_client(struct screen* s)
 60+{
 61+	struct client* c;
 62+
 63+	wl_list_for_each(c, &wm.clients, link) {
 64+		if (is_ws_client(c, s))
 65+			return c;
 66+	}
 67+
 68+	return NULL;
 69+}
 70+
 71+static bool is_ws_client(const struct client* c, const struct screen* s)
 72+{
 73+	return c && c->ws == wm.ws && (!s || c->scr == s);
 74+}
 75+
 76+static void on_screen_destroy(void* data)
 77+{
 78+	struct screen* s = data;
 79+
 80+	if (!s)
 81+		return;
 82+
 83+	wl_list_remove(&s->link);
 84+
 85+	if (wm.sel_screen == s) {
 86+		if (wl_list_empty(&wm.screens))
 87+			wm.sel_screen = NULL;
 88+		else
 89+			wm.sel_screen = wl_container_of(wm.screens.next, wm.sel_screen, link);
 90+	}
 91+
 92+	free(s);
 93+}
 94+
 95+static void on_win_destroy(void* data)
 96+{
 97+	struct client* c = data;
 98+	struct client* next;
 99+
100+	if (!c)
101+		return;
102+
103+	if (wm.grab.active && wm.grab.c == c) {
104+		wm.grab.active = false;
105+		wm.grab.c = NULL;
106+	}
107+
108+	if (wm.sel_client == c) {
109+		wm.sel_client = NULL;
110+	}
111+
112+	wl_list_remove(&c->link);
113+	free(c);
114+
115+	next = first_client(wm.sel_screen);
116+	if (!next)
117+		next = first_client(NULL);
118+	focus(next);
119+}
120+
121+static void on_win_entered(void* data)
122+{
123+	if (wm.grab.active)
124+		return;
125+
126+	struct client* c = data;
127+	if (!is_ws_client(c, NULL))
128+		return;
129+
130+	focus(c);
131+}
132+
133+static void setup(void)
134+{
135+	/* display */
136+	wm.dpy = wl_display_create();
137+	if (!wm.dpy)
138+		die(EXIT_FAILURE, "wl_display_create failed");
139+
140+	/* variables */
141+	wl_list_init(&wm.screens);
142+	wl_list_init(&wm.clients);
143+	wm.sel_client = NULL;
144+	wm.sel_screen = NULL;
145+	wm.grab.active = false;
146+	wm.grab.resize = false;
147+	wm.grab.c = NULL;
148+	wm.ws = 1;
149+
150+	/* event loop */
151+	wm.ev_loop = wl_display_get_event_loop(wm.dpy);
152+	if (!swc_initialize(wm.dpy, wm.ev_loop, &manager))
153+		die(EXIT_FAILURE, "swc_initialize failed\n");
154+
155+	setup_binds();
156+
157+	/* display socket */
158+	const char* sock;
159+	sock = wl_display_add_socket_auto(wm.dpy);
160+	if (!sock)
161+		die(EXIT_FAILURE, "wl_display_add_socket_auto failed\n");
162+	setenv("WAYLAND_DISPLAY", sock, 1);
163+	_log(stderr, "WAYLAND_DISPLAY=%s\n", sock);
164+
165+	/* signals */
166+	signal(SIGINT,  sig_handler);
167+	signal(SIGTERM, sig_handler);
168+	signal(SIGQUIT, sig_handler);
169+}
170+
171+static void setup_binds(void)
172+{
173+	for (size_t i = 0; i < LENGTH(binds); i++) {
174+		const struct bind* b = &binds[i];
175+		swc_add_binding(b->type, b->mods, b->ksym, b->fn, (void*)&b->arg);
176+	}
177+}
178+
179+static void sync_window_visibility(void)
180+{
181+	struct client* c;
182+
183+	wl_list_for_each(c, &wm.clients, link) {
184+		if (c->ws == wm.ws)
185+			swc_window_show(c->win);
186+		else
187+			swc_window_hide(c->win);
188+	}
189+}
190+
191+void focus_next(void* data, uint32_t time, uint32_t value, uint32_t state)
192+{
193+	(void)data;
194+	(void)time;
195+	(void)value;
196+
197+	struct client* c = NULL;
198+
199+	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
200+		return;
201+
202+	if (wl_list_empty(&wm.clients))
203+		return;
204+
205+	if (!wm.sel_client || !is_ws_client(wm.sel_client, wm.sel_screen)) {
206+		c = first_client(wm.sel_screen);
207+		if (!c)
208+			c = first_client(NULL);
209+		focus(c);
210+		return;
211+	}
212+
213+	struct wl_list* start = wm.sel_client->link.next;
214+	struct wl_list* it = start;
215+
216+	do {
217+		if (it == &wm.clients)
218+			it = wm.clients.next;
219+		if (it == &wm.clients)
220+			break;
221+
222+		c = wl_container_of(it, c, link);
223+		if (is_ws_client(c, wm.sel_screen)) {
224+			focus(c);
225+			return;
226+		}
227+		it = it->next;
228+	} while (it != start);
229+
230+	c = first_client(wm.sel_screen);
231+	if (!c)
232+		c = first_client(NULL);
233+	focus(c);
234+}
235+
236+void focus_prev(void* data, uint32_t time, uint32_t value, uint32_t state)
237+{
238+	struct client* c = NULL;
239+
240+	(void)data;
241+	(void)time;
242+	(void)value;
243+
244+	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
245+		return;
246+
247+	if (wl_list_empty(&wm.clients))
248+		return;
249+
250+	if (!wm.sel_client || !is_ws_client(wm.sel_client, wm.sel_screen)) {
251+		c = first_client(wm.sel_screen);
252+		if (!c)
253+			c = first_client(NULL);
254+		focus(c);
255+		return;
256+	}
257+
258+	struct wl_list* start = wm.sel_client->link.prev;
259+	struct wl_list* it = start;
260+
261+	do {
262+		if (it == &wm.clients)
263+			it = wm.clients.prev;
264+		if (it == &wm.clients)
265+			break;
266+
267+		c = wl_container_of(it, c, link);
268+		if (is_ws_client(c, wm.sel_screen)) {
269+			focus(c);
270+			return;
271+		}
272+		it = it->prev;
273+	} while (it != start);
274+
275+	c = first_client(wm.sel_screen);
276+	if (!c)
277+		c = first_client(NULL);
278+	focus(c);
279+}
280+
281+void kill_sel(void* data, uint32_t time, uint32_t value, uint32_t state)
282+{
283+	(void)data;
284+	(void)time;
285+	(void)value;
286+
287+	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
288+		return;
289+
290+	if (!wm.sel_client)
291+		return;
292+
293+	swc_window_close(wm.sel_client->win);
294+}
295+
296+void fullscreen(void* data, uint32_t time, uint32_t value, uint32_t state)
297+{
298+	struct swc_rectangle geom;
299+
300+	(void)data;
301+	(void)time;
302+	(void)value;
303+
304+	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
305+		return;
306+
307+	if (!wm.sel_client)
308+		return;
309+
310+	if (wm.sel_client->fullscreen) {
311+		wm.sel_client->fullscreen = false;
312+		swc_window_set_stacked(wm.sel_client->win);
313+
314+		if (wm.sel_client->w > 0 && wm.sel_client->h > 0) {
315+			geom.x = wm.sel_client->x;
316+			geom.y = wm.sel_client->y;
317+			geom.width = wm.sel_client->w;
318+			geom.height = wm.sel_client->h;
319+			swc_window_set_geometry(wm.sel_client->win, &geom);
320+		}
321+		return;
322+	}
323+
324+	if (!wm.sel_client->scr || !wm.sel_client->scr->scr)
325+		return;
326+
327+	if (swc_window_get_geometry(wm.sel_client->win, &geom)) {
328+		wm.sel_client->x = geom.x;
329+		wm.sel_client->y = geom.y;
330+		wm.sel_client->w = geom.width;
331+		wm.sel_client->h = geom.height;
332+	}
333+
334+	wm.sel_client->fullscreen = true;
335+	swc_window_set_fullscreen(wm.sel_client->win, wm.sel_client->scr->scr);
336+}
337+
338+/* slgro - im sure i could have made this better but atleast this works rn so ig that's what matters,, ill work on simplifying this another time,.,.*/
339+void kb_move_x(void* data, uint32_t time, uint32_t value, uint32_t state) {
340+
341+	(void)time;
342+	(void)value;
343+
344+	union arg* a = data;
345+	struct swc_rectangle geom;
346+
347+	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
348+		return;
349+
350+	if (!wm.sel_client)
351+		return;
352+
353+	if (swc_window_get_geometry(wm.sel_client->win, &geom)) {
354+		geom.x += a->i;
355+		swc_window_set_geometry(wm.sel_client->win, &geom);
356+	}
357+
358+}
359+
360+void kb_move_y(void* data, uint32_t time, uint32_t value, uint32_t state) {
361+
362+	(void)time;
363+	(void)value;
364+	
365+	union arg* a = data;
366+	struct swc_rectangle geom;
367+
368+	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
369+		return;
370+
371+	if (!wm.sel_client)
372+		return;
373+
374+	if (swc_window_get_geometry(wm.sel_client->win, &geom)) {
375+		geom.y += a->i;
376+		swc_window_set_geometry(wm.sel_client->win, &geom);
377+	}
378+
379+}
380+
381+/* slgro - same thing here, ill figure out how to simplify this into one function another time, just focusing on making this work to begin with for now*/
382+void kb_resize_width(void* data, uint32_t time, uint32_t value, uint32_t state) {
383+
384+	(void)time;
385+	(void)value;
386+
387+	union arg* a = data;
388+	struct swc_rectangle geom;
389+
390+	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
391+		return;
392+
393+	if (!wm.sel_client)
394+		return;
395+
396+	if (swc_window_get_geometry(wm.sel_client->win, &geom)) {
397+		geom.width += a->i;
398+		swc_window_set_geometry(wm.sel_client->win, &geom);
399+	}
400+
401+}
402+
403+void kb_resize_height(void* data, uint32_t time, uint32_t value, uint32_t state) {
404+
405+	(void)time;
406+	(void)value;
407+
408+	union arg* a = data;
409+	struct swc_rectangle geom;
410+
411+	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
412+		return;
413+
414+	if (!wm.sel_client)
415+		return;
416+
417+	if (swc_window_get_geometry(wm.sel_client->win, &geom)) {
418+		geom.height += a->i;
419+		swc_window_set_geometry(wm.sel_client->win, &geom);
420+	}
421+
422+}
423+
424+/* slgro - idk if this is THAT useful but its kinda useful for me so that's what matters i suppose,,*/
425+void center_window(void* data, uint32_t time, uint32_t value, uint32_t state) {
426+
427+	(void)data;
428+	(void)value;
429+	(void)state;
430+	(void)time;
431+
432+	struct swc_rectangle geom;
433+
434+	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
435+		return;
436+
437+	if (!wm.sel_client)
438+		return;
439+
440+	if (swc_window_get_geometry(wm.sel_client->win, &geom)) {
441+		geom.x = (wm.sel_client->scr->scr->usable_geometry.width / 2) - (geom.width / 2);
442+		geom.y = (wm.sel_client->scr->scr->usable_geometry.height / 2) - (geom.height / 2);
443+		swc_window_set_geometry(wm.sel_client->win, &geom);
444+	}
445+
446+}
447+
448+/* slgro - very experimental snapping, will prob refactor this at some point */ 
449+void snap_left_half(void* data, uint32_t time, uint32_t value, uint32_t state) {
450+
451+(void)data;
452+(void)value;
453+(void)state;
454+(void)time;
455+
456+struct swc_rectangle geom;
457+
458+if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
459+return;
460+
461+if (!wm.sel_client)
462+return;
463+
464+	geom.x = wm.sel_client->scr->scr->usable_geometry.x;
465+	geom.y = wm.sel_client->scr->scr->usable_geometry.y;
466+	geom.width = wm.sel_client->scr->scr->usable_geometry.width / 2;
467+	geom.height = wm.sel_client->scr->scr->usable_geometry.height;
468+	swc_window_set_geometry(wm.sel_client->win, &geom);
469+
470+}
471+
472+void snap_right_half(void* data, uint32_t time, uint32_t value, uint32_t state) {
473+
474+(void)data;
475+(void)value;
476+(void)state;
477+(void)time;
478+
479+struct swc_rectangle geom;
480+
481+if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
482+return;
483+
484+if (!wm.sel_client)
485+return;
486+
487+geom.x = wm.sel_client->scr->scr->usable_geometry.width / 2;
488+geom.y = wm.sel_client->scr->scr->usable_geometry.y;
489+geom.width = wm.sel_client->scr->scr->usable_geometry.width / 2;
490+geom.height = wm.sel_client->scr->scr->usable_geometry.height;
491+swc_window_set_geometry(wm.sel_client->win, &geom);
492+
493+}
494+
495+void new_screen(struct swc_screen* scr)
496+{
497+	struct screen* s;
498+
499+	s = malloc(sizeof(*s));
500+	if (!s)
501+		die(EXIT_FAILURE, "new screen calloc failed");
502+
503+	s->scr = scr;
504+
505+	s->x = 0;
506+	s->y = 0;
507+	s->w = 0;
508+	s->h = 0;
509+
510+	wl_list_insert(&wm.screens, &s->link);
511+
512+	if (!wm.sel_screen)
513+		wm.sel_screen = s;
514+
515+	swc_screen_set_handler(scr, &screen_handler, s);
516+
517+	_log(stderr, "new_screen=%p\n", (void*)scr);
518+}
519+
520+void new_window(struct swc_window* win)
521+{
522+	struct client* c;
523+
524+	c = malloc(sizeof(*c));
525+	if (!c)
526+		die(EXIT_FAILURE, "malloc client failed");
527+
528+	win->motion_throttle_ms = 1000 / cfg.motion_throttle_hz;
529+	win->min_width = 1;
530+	win->min_height = 1;
531+	win->max_width = 0;
532+	win->max_height = 0;
533+
534+	c->win = win;
535+	c->scr = wm.sel_screen;
536+	c->mapped = 0;
537+	c->floating = true;
538+	c->fullscreen = 0;
539+	c->ws = wm.ws;
540+	c->x = 0;
541+	c->y = 0;
542+	c->w = 0;
543+	c->h = 0;
544+
545+	wl_list_insert(&wm.clients, &c->link);
546+	swc_window_set_handler(win, &window_handler, c);
547+	swc_window_set_stacked(win);
548+	{
549+		/* swc reports cursor coordinates in wl_fixed_t (24.8) units */
550+		int32_t cx_fixed = 0;
551+		int32_t cy_fixed = 0;
552+
553+		if (swc_cursor_position(&cx_fixed, &cy_fixed))
554+			swc_window_set_position(win, cx_fixed / 256, cy_fixed / 256);
555+	}
556+	swc_window_show(win);
557+	focus(c);
558+
559+	_log(stderr, "new_window=%p\n", (void*)win);
560+}
561+
562+void new_device(struct libinput_device* dev)
563+{
564+	(void)dev;
565+}
566+
567+void quit(void* data, uint32_t time, uint32_t value, uint32_t state)
568+{
569+	(void)data;
570+	(void)time;
571+	(void)value;
572+	(void)state;
573+
574+	wl_display_terminate(wm.dpy);
575+}
576+
577+void spawn(void* data, uint32_t time, uint32_t value, uint32_t state)
578+{
579+	union arg* a = data;
580+	char* const* cmd = (char* const*)a->v;
581+
582+	(void)time;
583+	(void)value;
584+
585+	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
586+		return;
587+
588+	if (fork() == 0) {
589+		execvp(cmd[0], cmd);
590+		_exit(127);
591+	}
592+}
593+
594+void workspace_goto(void* data, uint32_t time, uint32_t value, uint32_t state)
595+{
596+	union arg* a = data;
597+	struct client* c;
598+
599+	(void)time;
600+	(void)value;
601+
602+	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
603+		return;
604+
605+	if (a->ui < 1 || a->ui > 9 || a->ui == wm.ws)
606+		return;
607+
608+	wm.ws = a->ui;
609+	sync_window_visibility();
610+
611+	c = first_client(wm.sel_screen);
612+	if (!c)
613+		c = first_client(NULL);
614+	focus(c);
615+}
616+
617+void workspace_moveto(void* data, uint32_t time, uint32_t value, uint32_t state)
618+{
619+	union arg* a = data;
620+	struct client* c;
621+	struct client* next;
622+
623+	(void)time;
624+	(void)value;
625+
626+	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
627+		return;
628+
629+	if (!wm.sel_client)
630+		return;
631+
632+	if (a->ui < 1 || a->ui > 9)
633+		return;
634+
635+	c = wm.sel_client;
636+	if (c->ws == a->ui)
637+		return;
638+
639+	c->ws = a->ui;
640+	if (c->ws == wm.ws)
641+		swc_window_show(c->win);
642+	else
643+		swc_window_hide(c->win);
644+
645+	next = first_client(wm.sel_screen);
646+	if (!next)
647+		next = first_client(NULL);
648+	focus(next);
649+}
650+
651+int main(void)
652+{
653+	setup();
654+	wl_display_run(wm.dpy);
655+	swc_finalize();
656+	wl_display_destroy(wm.dpy);
657+	return EXIT_SUCCESS;
658+}
+44, -0
 1@@ -0,0 +1,44 @@
 2+#include <stdlib.h>
 3+
 4+#include <swc.h>
 5+
 6+#include "include/util.h"
 7+#include "include/slgro.h"
 8+
 9+void die(int ret, const char* fmt, ...)
10+{
11+	va_list ap;
12+
13+	fprintf(stderr, "slgro: ");
14+
15+	va_start(ap, fmt);
16+	vfprintf(stderr, fmt, ap);
17+	va_end(ap);
18+
19+	fputc('\n', stderr);
20+	fflush(stderr);
21+
22+	exit(ret);
23+}
24+
25+void _log(FILE* fd, const char* fmt, ...)
26+{
27+	va_list ap;
28+
29+	fprintf(fd, "slgro: ");
30+
31+	va_start(ap, fmt);
32+	vfprintf(fd, fmt, ap);
33+	va_end(ap);
34+
35+	fputc('\n', fd);
36+	fflush(fd);
37+}
38+
39+void sig_handler(int s)
40+{
41+	(void)s;
42+
43+	if (wm.dpy)
44+		wl_display_terminate(wm.dpy);
45+}