commit 10a9cf4

0uppy  ·  2026-03-13 20:36:44 +0000 UTC
parent 99ec8e9
Previous commit was broken bc im dumb + Yayy i got (A HUGE) help yayy :3

Thank you Unc (https://github.com/pascalecu) for helping me out aswell :sob: 
Now slgro is like..,,., 150+ ish LOC smaller woo :3
1 files changed,  +289, -436
+289, -436
  1@@ -1,7 +1,9 @@
  2+#include <asm-generic/errno.h>
  3 #include <signal.h>
  4 #include <stdio.h>
  5 #include <stdlib.h>
  6 #include <unistd.h>
  7+#include <sys/wait.h>
  8 
  9 #include <swc.h>
 10 #include <wayland-server.h>
 11@@ -13,8 +15,6 @@
 12 #include "include/util.h"
 13 #include "include/slgro.h"
 14 
 15-#define VOID(...) (void)(__VA_ARGS__)
 16-
 17 static void focus(struct client* c);
 18 static struct client* first_client(struct screen* s);
 19 static bool is_ws_client(const struct client* c, const struct screen* s);
 20@@ -25,598 +25,451 @@ static void setup(void);
 21 static void setup_binds(void);
 22 static void sync_window_visibility(void);
 23 
 24+#define WHEN_PRESSED(state) \
 25+	do { if ((state) != WL_KEYBOARD_KEY_STATE_PRESSED) return; } while (0)
 26+
 27+#define BIND_EVENT(time, value, state) \
 28+	(void)(time); (void)(value); \
 29+	WHEN_PRESSED(state);
 30+
 31+#define BIND_ACTION(data, time, value, state) \
 32+	BIND_EVENT(time, value, state); \
 33+	if (!wm.sel_client) return; \
 34+	union arg* a = (data)
 35+
 36+/* read geometry from client window; returns true if successful */
 37+static bool get_geometry(struct client *c, struct swc_rectangle *geom)
 38+{
 39+	if (!c || !c->win)
 40+		return false;
 41+
 42+	return swc_window_get_geometry(c->win, geom);
 43+}
 44+
 45+/* adjust geometry fields and write back */
 46+static void adjust_geom(struct client *c, int dx, int dy, int dw, int dh)
 47+{
 48+	struct swc_rectangle geom;
 49+	if (!get_geometry(c, &geom)) return;
 50+
 51+	geom.x += dx;
 52+	geom.y += dy;
 53+
 54+	int new_w = (int)geom.width + dw;
 55+	int new_h = (int)geom.height + dh;
 56+	geom.width = (new_w < 1) ? 1 : (uint32_t)new_w;
 57+	geom.height = (new_h < 1) ? 1 : (uint32_t)new_h;
 58+
 59+	swc_window_set_geometry(c->win, &geom);
 60+}
 61+
 62 struct wm wm;
 63 const struct swc_manager manager = {
 64-.new_screen = new_screen, .new_window = new_window, .new_device = new_devic
 65-e,
 66+	.new_screen = new_screen, .new_window = new_window, .new_device = new_device,
 67 };
 68 struct swc_window_handler window_handler = {
 69-.destroy = on_win_destroy, .entered = on_win_entered,
 70+	.destroy = on_win_destroy, .entered = on_win_entered,
 71 };
 72 struct swc_screen_handler screen_handler = {
 73-.destroy = on_screen_destroy,
 74+	.destroy = on_screen_destroy,
 75 };
 76 
 77+static struct client* get_focus_candidate(struct screen* s) {
 78+	struct client* c = first_client(s);
 79+	if (!c && s) c = first_client(NULL);
 80+	return c;
 81+}
 82+
 83 static void focus(struct client* c)
 84 {
 85-if (wm.sel_client)
 86-swc_window_set_border(
 87-wm.sel_client->win,
 88-cfg.border_col_normal, cfg.border_width,
 89-0, 0
 90-);
 91-
 92-if (c)
 93-swc_window_set_border(
 94-c->win,
 95-cfg.border_col_active, cfg.border_width,
 96-0, 0
 97-);
 98+	if (wm.sel_client && wm.sel_client != c) {
 99+		swc_window_set_border(wm.sel_client->win, cfg.border_col_normal, cfg.border_width, 0, 0);
100+	}
101+	if (c) {
102+		swc_window_set_border(c->win, cfg.border_col_active, cfg.border_width, 0, 0);
103+	}
104 
105-swc_window_focus(c ? c->win : NULL);
106-wm.sel_client = c;
107+	swc_window_focus(c ? c->win : NULL);
108+	wm.sel_client = c;
109 }
110 
111 static struct client* first_client(struct screen* s)
112 {
113-struct client* c;
114+	struct client* c;
115 
116-wl_list_for_each(c, &wm.clients, link) {
117-if (is_ws_client(c, s))
118-return c;
119-}
120+	wl_list_for_each(c, &wm.clients, link) {
121+		if (is_ws_client(c, s))
122+			return c;
123+	}
124 
125-return NULL;
126+	return NULL;
127 }
128 
129 static bool is_ws_client(const struct client* c, const struct screen* s)
130 {
131-return c && c->ws == wm.ws && (!s || c->scr == s);
132+	return c && c->ws == wm.ws && (!s || c->scr == s);
133 }
134 
135 static void on_screen_destroy(void* data)
136 {
137-struct screen* s = data;
138+	struct screen* s = data;
139 
140-if (!s)
141-return;
142+	if (!s)
143+		return;
144 
145-wl_list_remove(&s->link);
146+	wl_list_remove(&s->link);
147 
148-if (wm.sel_screen == s) {
149-if (wl_list_empty(&wm.screens))
150-wm.sel_screen = NULL;
151-else
152-wm.sel_screen = wl_container_of(wm.screens.next, wm.sel_scr
153-een, link);
154-}
155+	if (wm.sel_screen == s) {
156+		wm.sel_screen = wl_list_empty(&wm.screens)
157+			? NULL
158+			: wl_container_of(wm.screens.next, wm.sel_screen, link);
159+	}
160 
161-free(s);
162+	free(s);
163 }
164 
165 static void on_win_destroy(void* data)
166 {
167-struct client* c = data;
168-struct client* next;
169-
170-if (!c)
171-return;
172+	struct client* c = data;
173+	if (!c) return;
174 
175-if (wm.grab.active && wm.grab.c == c) {
176-wm.grab.active = false;
177-wm.grab.c = NULL;
178-}
179+	if (wm.grab.active && wm.grab.c == c)
180+		wm.grab.active = false;
181 
182-if (wm.sel_client == c)
183-wm.sel_client = NULL;
184+	if (wm.sel_client == c)
185+		wm.sel_client = NULL;
186 
187-wl_list_remove(&c->link);
188-free(c);
189+	wl_list_remove(&c->link);
190+	free(c);
191 
192-next = first_client(wm.sel_screen);
193-if (!next)
194-next = first_client(NULL);
195-focus(next);
196+	focus(get_focus_candidate(wm.sel_screen));
197 }
198 
199 static void on_win_entered(void* data)
200 {
201-if (wm.grab.active)
202-return;
203+	if (wm.grab.active)
204+		return;
205 
206-struct client* c = data;
207-if (!is_ws_client(c, NULL))
208-return;
209+	struct client* c = data;
210+	if (!is_ws_client(c, NULL))
211+		return;
212 
213-focus(c);
214+	focus(c);
215 }
216 
217 static void setup(void)
218 {
219-wm.dpy = wl_display_create();
220-if (!wm.dpy)
221-die(EXIT_FAILURE, "wl_display_create failed");
222+	/* display */
223+	wm.dpy = wl_display_create();
224+	if (!wm.dpy)
225+		die(EXIT_FAILURE, "wl_display_create failed");
226 
227-wl_list_init(&wm.screens);
228-wl_list_init(&wm.clients);
229-wm.sel_client = NULL;
230-wm.sel_screen = NULL;
231-wm.grab.active = false;
232-wm.grab.resize = false;
233-wm.grab.c = NULL;
234-wm.ws = 1;
235+	/* variables */
236+	wl_list_init(&wm.screens);
237+	wl_list_init(&wm.clients);
238 
239-wm.ev_loop = wl_display_get_event_loop(wm.dpy);
240-if (!swc_initialize(wm.dpy, wm.ev_loop, &manager))
241-die(EXIT_FAILURE, "swc_initialize failed\n");
242+	wm.sel_client = NULL;
243+	wm.sel_screen = NULL;
244+	wm.grab.active = false;
245+	wm.grab.resize = false;
246+	wm.grab.c = NULL;
247+	wm.ws = 1;
248 
249-setup_binds();
250+	/* event loop */
251+	wm.ev_loop = wl_display_get_event_loop(wm.dpy);
252+	if (!swc_initialize(wm.dpy, wm.ev_loop, &manager))
253+		die(EXIT_FAILURE, "swc_initialize failed\n");
254 
255-const char* sock;
256-sock = wl_display_add_socket_auto(wm.dpy);
257-if (!sock)
258-die(EXIT_FAILURE, "wl_display_add_socket_auto failed\n");
259-setenv("WAYLAND_DISPLAY", sock, 1);
260-_log(stderr, "WAYLAND_DISPLAY=%s\n", sock);
261+	setup_binds();
262 
263-signal(SIGINT,  sig_handler);
264-signal(SIGTERM, sig_handler);
265-signal(SIGQUIT, sig_handler);
266+	/* display socket */
267+	const char* sock;
268+	sock = wl_display_add_socket_auto(wm.dpy);
269+	if (!sock)
270+		die(EXIT_FAILURE, "wl_display_add_socket_auto failed\n");
271+
272+	setenv("WAYLAND_DISPLAY", sock, 1);
273+	_log(stderr, "WAYLAND_DISPLAY=%s\n", sock);
274+
275+	/* signals */
276+	signal(SIGINT,  sig_handler);
277+	signal(SIGTERM, sig_handler);
278+	signal(SIGQUIT, sig_handler);
279 }
280 
281 static void setup_binds(void)
282 {
283-for (size_t i = 0; i < LENGTH(binds); i++) {
284-const struct bind* b = &binds[i];
285-swc_add_binding(b->type, b->mods, b->ksym, b->fn, (void*)&b->arg);
286-}
287+	for (size_t i = 0; i < LENGTH(binds); i++) {
288+		const struct bind* b = &binds[i];
289+		swc_add_binding(b->type, b->mods, b->ksym, b->fn, (void*)&b->arg);
290+	}
291 }
292 
293 static void sync_window_visibility(void)
294 {
295-struct client* c;
296+	struct client* c;
297 
298-wl_list_for_each(c, &wm.clients, link) {
299-if (c->ws == wm.ws)
300-swc_window_show(c->win);
301-else
302-swc_window_hide(c->win);
303-}
304+	wl_list_for_each(c, &wm.clients, link) {
305+		if (c->ws == wm.ws)
306+			swc_window_show(c->win);
307+		else
308+			swc_window_hide(c->win);
309+	}
310 }
311 
312-void focus_next(void* data, uint32_t time, uint32_t value, uint32_t state)
313+
314+/* focus next/prev helpers */
315+static void focus_walk_direction(bool forward)
316 {
317-VOID(data, time, value);
318+	if (wl_list_empty(&wm.clients)) return;
319 
320-struct client* c = NULL;
321+	if (!is_ws_client(wm.sel_client, wm.sel_screen)) {
322+		focus(get_focus_candidate(wm.sel_screen));
323+		return;
324+	}
325 
326-if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
327-return;
328+	struct wl_list *start =
329+		forward ? wm.sel_client->link.next
330+				: wm.sel_client->link.prev;
331 
332-if (wl_list_empty(&wm.clients))
333-return;
334+	struct wl_list *it = start;
335+	struct client *c = NULL;
336 
337-if (!wm.sel_client || !is_ws_client(wm.sel_client, wm.sel_screen)) {
338-c = first_client(wm.sel_screen);
339-if (!c)
340-c = first_client(NULL);
341-focus(c);
342-return;
343-}
344+	do {
345+		if (it == &wm.clients)
346+			it = forward ? wm.clients.next : wm.clients.prev;
347 
348-struct wl_list* start = wm.sel_client->link.next;
349-struct wl_list* it = start;
350+		if (it == &wm.clients) break;
351 
352-do {
353-if (it == &wm.clients)
354-it = wm.clients.next;
355-if (it == &wm.clients)
356-break;
357+		c = wl_container_of(it, c, link);
358+		if (is_ws_client(c, wm.sel_screen)) {
359+			focus(c);
360+			return;
361+		}
362 
363-c = wl_container_of(it, c, link);
364-if (is_ws_client(c, wm.sel_screen)) {
365-focus(c);
366-return;
367-}
368-it = it->next;
369-} while (it != start);
370+		it = forward ? it->next : it->prev;
371+	} while (it != start);
372 
373-c = first_client(wm.sel_screen);
374-if (!c)
375-c = first_client(NULL);
376-focus(c);
377+	focus(get_focus_candidate(wm.sel_screen));
378 }
379 
380-void focus_prev(void* data, uint32_t time, uint32_t value, uint32_t state)
381+void focus_next(void* data, uint32_t time, uint32_t value, uint32_t state)
382 {
383-VOID(data, time, value);
384-
385-struct client* c = NULL;
386-
387-if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
388-return;
389-
390-if (wl_list_empty(&wm.clients))
391-return;
392-
393-if (!wm.sel_client || !is_ws_client(wm.sel_client, wm.sel_screen)) {
394-c = first_client(wm.sel_screen);
395-if (!c)
396-c = first_client(NULL);
397-focus(c);
398-return;
399+	(void)data; BIND_EVENT(time, value, state);
400+	focus_walk_direction(true);
401 }
402 
403-struct wl_list* start = wm.sel_client->link.prev;
404-struct wl_list* it = start;
405-
406-do {
407-if (it == &wm.clients)
408-it = wm.clients.prev;
409-if (it == &wm.clients)
410-break;
411-
412-c = wl_container_of(it, c, link);
413-if (is_ws_client(c, wm.sel_screen)) {
414-focus(c);
415-return;
416-}
417-it = it->prev;
418-} while (it != start);
419-
420-c = first_client(wm.sel_screen);
421-if (!c)
422-c = first_client(NULL);
423-focus(c);
424+void focus_prev(void* data, uint32_t time, uint32_t value, uint32_t state)
425+{
426+	(void)data; BIND_EVENT(time, value, state);
427+	focus_walk_direction(false);
428 }
429 
430 void kill_sel(void* data, uint32_t time, uint32_t value, uint32_t state)
431 {
432-VOID(data, time, value);
433-
434-if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
435-return;
436+	(void)data; BIND_EVENT(time, value, state);
437 
438-if (!wm.sel_client)
439-return;
440-
441-swc_window_close(wm.sel_client->win);
442+	if (wm.sel_client)
443+		swc_window_close(wm.sel_client->win);
444 }
445 
446 void fullscreen(void* data, uint32_t time, uint32_t value, uint32_t state)
447 {
448-VOID(data, time, value);
449+	(void)data; BIND_EVENT(time, value, state);
450+	if (!wm.sel_client) return;
451 
452-struct swc_rectangle geom;
453+	struct client *c = wm.sel_client;
454+	struct swc_rectangle geom;
455 
456-if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
457-return;
458+	if (c->fullscreen) {
459+		c->fullscreen = false;
460+		swc_window_set_stacked(c->win);
461 
462-if (!wm.sel_client)
463-return;
464+		if (c->w > 0 && c->h > 0) {
465+			geom = (struct swc_rectangle){ c->x, c->y, c->w, c->h };
466+			swc_window_set_geometry(c->win, &geom);
467+		}
468+		return;
469+	}
470 
471-if (wm.sel_client->fullscreen) {
472-wm.sel_client->fullscreen = false;
473-swc_window_set_stacked(wm.sel_client->win);
474+	if (!c->scr || !c->scr->scr) return;
475 
476-if (wm.sel_client->w > 0 && wm.sel_client->h > 0) {
477-geom.x = wm.sel_client->x;
478-geom.y = wm.sel_client->y;
479-geom.width = wm.sel_client->w;
480-geom.height = wm.sel_client->h;
481-swc_window_set_geometry(wm.sel_client->win, &geom);
482-}
483-return;
484-}
485+	if (get_geometry(c, &geom)) {
486+		c->x = geom.x;
487+		c->y = geom.y;
488+		c->w = geom.width;
489+		c->h = geom.height;
490+	}
491 
492-if (!wm.sel_client->scr || !wm.sel_client->scr->scr)
493-return;
494-
495-if (swc_window_get_geometry(wm.sel_client->win, &geom)) {
496-wm.sel_client->x = geom.x;
497-wm.sel_client->y = geom.y;
498-wm.sel_client->w = geom.width;
499-wm.sel_client->h = geom.height;
500+	c->fullscreen = true;
501+	swc_window_set_fullscreen(c->win, c->scr->scr);
502 }
503 
504-wm.sel_client->fullscreen = true;
505-swc_window_set_fullscreen(wm.sel_client->win, wm.sel_client->scr->scr);
506+void kb_move_x(void* data, uint32_t time, uint32_t value, uint32_t state) {
507+	BIND_ACTION(data, time, value, state);
508+	adjust_geom(wm.sel_client, a->i, 0, 0, 0);
509 }
510 
511-/* slgro - im sure i could have made this better but atleast this works rn so ig th
512-at's what matters,, ill work on simplifying this another time,.,.*/
513-void kb_move_x(void* data, uint32_t time, uint32_t value, uint32_t state)
514-{
515-VOID(time, value);
516-
517-union arg* a = data;
518-struct swc_rectangle geom;
519-
520-if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
521-return;
522-
523-if (!wm.sel_client)
524-return;
525-
526-if (swc_window_get_geometry(wm.sel_client->win, &geom)) {
527-geom.x += a->i;
528-swc_window_set_geometry(wm.sel_client->win, &geom);
529-}
530+void kb_move_y(void* data, uint32_t time, uint32_t value, uint32_t state) {
531+	BIND_ACTION(data, time, value, state);
532+	adjust_geom(wm.sel_client, 0, a->i, 0, 0);
533 }
534 
535-void kb_move_y(void* data, uint32_t time, uint32_t value, uint32_t state)
536-{
537-VOID(time, value);
538-
539-union arg* a = data;
540-struct swc_rectangle geom;
541-
542-if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
543-return;
544-
545-if (!wm.sel_client)
546-return;
547-
548-if (swc_window_get_geometry(wm.sel_client->win, &geom)) {
549-geom.y += a->i;
550-swc_window_set_geometry(wm.sel_client->win, &geom);
551-}
552+void kb_resize_width(void* data, uint32_t time, uint32_t value, uint32_t state) {
553+	BIND_ACTION(data, time, value, state);
554+	adjust_geom(wm.sel_client, 0, 0, a->i, 0);
555 }
556 
557-/* slgro - same thing here, ill figure out how to simplify this into one function a
558-nother time, just focusing on making this work to begin with for now*/
559-void kb_resize_width(void* data, uint32_t time, uint32_t value, uint32_t state)
560-{
561-VOID(time, value);
562-
563-union arg* a = data;
564-struct swc_rectangle geom;
565-
566-if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
567-return;
568-
569-if (!wm.sel_client)
570-return;
571-
572-if (swc_window_get_geometry(wm.sel_client->win, &geom)) {
573-geom.width += a->i;
574-swc_window_set_geometry(wm.sel_client->win, &geom);
575-}
576+void kb_resize_height(void* data, uint32_t time, uint32_t value, uint32_t state) {
577+	BIND_ACTION(data, time, value, state);
578+	adjust_geom(wm.sel_client, 0, 0, 0, a->i);
579 }
580 
581-void kb_resize_height(void* data, uint32_t time, uint32_t value, uint32_t state)
582-{
583-VOID(time, value);
584+static void apply_grid_geometry(struct client *c, float x_frac, float w_frac) {
585+	if (!c || !c->scr || !c->scr->scr) return;
586 
587-union arg* a = data;
588-struct swc_rectangle geom;
589+	struct swc_rectangle geom;
590+	struct swc_rectangle *ug = &c->scr->scr->usable_geometry;
591 
592-if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
593-return;
594+	geom.x = ug->x + (ug->width * x_frac);
595+	geom.y = ug->y;
596+	geom.width = ug->width * w_frac;
597+	geom.height = ug->height;
598 
599-if (!wm.sel_client)
600-return;
601-
602-if (swc_window_get_geometry(wm.sel_client->win, &geom)) {
603-geom.height += a->i;
604-swc_window_set_geometry(wm.sel_client->win, &geom);
605-}
606+	swc_window_set_geometry(c->win, &geom);
607 }
608 
609-/* slgro - idk if this is THAT useful but its kinda useful for me so that's what ma
610-tters i suppose,,*/
611-void center_window(void* data, uint32_t time, uint32_t value, uint32_t state)
612-{
613-VOID(data, time, value);
614+void center_window(void* data, uint32_t time, uint32_t value, uint32_t state) {
615+	BIND_ACTION(data, time, value, state);
616+	if (!wm.sel_client->scr || !wm.sel_client->scr->scr) return;
617 
618-struct swc_rectangle geom;
619+	struct swc_rectangle geom;
620+	if (!get_geometry(wm.sel_client, &geom)) return;
621 
622-if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
623-return;
624+	struct swc_rectangle *ug = &wm.sel_client->scr->scr->usable_geometry;
625+	geom.x = ug->x + (ug->width - geom.width) / 2;
626+	geom.y = ug->y + (ug->height - geom.height) / 2;
627 
628-if (!wm.sel_client)
629-return;
630-
631-if (swc_window_get_geometry(wm.sel_client->win, &geom)) {
632-geom.x = (wm.sel_client->scr->scr->usable_geometry.width / 2) - (ge
633-om.width / 2);
634-geom.y = (wm.sel_client->scr->scr->usable_geometry.height / 2) - (g
635-eom.height / 2);
636-swc_window_set_geometry(wm.sel_client->win, &geom);
637-}
638+	swc_window_set_geometry(wm.sel_client->win, &geom);
639 }
640 
641-/* slgro - very experimental snapping, will prob refactor this at some point */
642-void snap_left_half(void* data, uint32_t time, uint32_t value, uint32_t state)
643-{
644-VOID(data, time, value);
645-
646-struct swc_rectangle geom;
647-
648-if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
649-return;
650-
651-if (!wm.sel_client)
652-return;
653+void snap_left_half(void* data, uint32_t time, uint32_t value, uint32_t state) {
654+	BIND_ACTION(data, time, value, state);
655+	apply_grid_geometry(wm.sel_client, 0.0f, 0.5f);
656+}
657 
658-geom.x = wm.sel_client->scr->scr->usable_geometry.x;
659-geom.y = wm.sel_client->scr->scr->usable_geometry.y;
660-geom.width = wm.sel_client->scr->scr->usable_geometry.width / 2;
661-geom.height = wm.sel_client->scr->scr->usable_geometry.height;
662-swc_window_set_geometry(wm.sel_client->win, &geom);
663+void snap_right_half(void* data, uint32_t time, uint32_t value, uint32_t state) {
664+	BIND_ACTION(data, time, value, state);
665+	apply_grid_geometry(wm.sel_client, 0.5f, 0.5f);
666 }
667 
668-void snap_right_half(void* data, uint32_t time, uint32_t value, uint32_t state)
669+void new_screen(struct swc_screen* scr)
670 {
671-VOID(data, time, value);
672+	struct screen* s = calloc(1, sizeof(*s));
673+	if (!s) die(EXIT_FAILURE, "new screen calloc failed");
674 
675-struct swc_rectangle geom;
676+	s->scr = scr;
677+	wl_list_insert(&wm.screens, &s->link);
678 
679-if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
680-return;
681+	if (!wm.sel_screen) wm.sel_screen = s;
682 
683-if (!wm.sel_client)
684-return;
685-
686-geom.x = wm.sel_client->scr->scr->usable_geometry.width / 2;
687-geom.y = wm.sel_client->scr->scr->usable_geometry.y;
688-geom.width = wm.sel_client->scr->scr->usable_geometry.width / 2;
689-geom.height = wm.sel_client->scr->scr->usable_geometry.height;
690-swc_window_set_geometry(wm.sel_client->win, &geom);
691+	swc_screen_set_handler(scr, &screen_handler, s);
692+	_log(stderr, "new_screen=%p\n", (void*)scr);
693 }
694 
695-void new_screen(struct swc_screen* scr)
696+void new_window(struct swc_window* win)
697 {
698-struct screen* s;
699+	struct client* c = calloc(1, sizeof(*c));
700+	if (!c) die(EXIT_FAILURE, "calloc client failed");
701 
702-s = malloc(sizeof(*s));
703-if (!s)
704-die(EXIT_FAILURE, "new screen calloc failed");
705+	win->motion_throttle_ms = 1000 / cfg.motion_throttle_hz;
706+	win->min_width = 1;
707+	win->min_height = 1;
708 
709-s->scr = scr;
710-s->x = 0;
711-s->y = 0;
712-s->w = 0;
713-s->h = 0;
714+	c->win = win;
715+	c->scr = wm.sel_screen;
716+	c->floating = true;
717+	c->ws = wm.ws;
718 
719-wl_list_insert(&wm.screens, &s->link);
720+	wl_list_insert(&wm.clients, &c->link);
721+	swc_window_set_handler(win, &window_handler, c);
722+	swc_window_set_stacked(win);
723 
724-if (!wm.sel_screen)
725-wm.sel_screen = s;
726+	int32_t cx = 0, cy = 0;
727+	if (swc_cursor_position(&cx, &cy))
728+		swc_window_set_position(win, cx / 256, cy / 256);
729 
730-swc_screen_set_handler(scr, &screen_handler, s);
731-_log(stderr, "new_screen=%p\n", (void*)scr);
732-}
733+	swc_window_show(win);
734+	focus(c);
735 
736-void new_window(struct swc_window* win)
737-{
738-struct client* c;
739-
740-c = malloc(sizeof(*c));
741-if (!c)
742-die(EXIT_FAILURE, "malloc client failed");
743-
744-win->motion_throttle_ms = 1000 / cfg.motion_throttle_hz;
745-win->min_width = 1;
746-win->min_height = 1;
747-win->max_width = 0;
748-win->max_height = 0;
749-
750-c->win = win;
751-c->scr = wm.sel_screen;
752-c->mapped = 0;
753-c->floating = true;
754-c->fullscreen = 0;
755-c->ws = wm.ws;
756-c->x = 0;
757-c->y = 0;
758-c->w = 0;
759-c->h = 0;
760-
761-wl_list_insert(&wm.clients, &c->link);
762-swc_window_set_handler(win, &window_handler, c);
763-swc_window_set_stacked(win);
764-{
765-/* swc reports cursor coordinates in wl_fixed_t (24.8) units */
766-int32_t cx_fixed = 0;
767-int32_t cy_fixed = 0;
768-
769-if (swc_cursor_position(&cx_fixed, &cy_fixed))
770-swc_window_set_position(win, cx_fixed / 256, cy_fixed / 256
771-);
772-}
773-swc_window_show(win);
774-focus(c);
775-_log(stderr, "new_window=%p\n", (void*)win);
776+	_log(stderr, "new_window=%p\n", (void*)win);
777 }
778 
779 void new_device(struct libinput_device* dev)
780 {
781-(void)dev;
782+	(void)dev;
783 }
784 
785 void quit(void* data, uint32_t time, uint32_t value, uint32_t state)
786 {
787-VOID(data, time, value, state);
788-wl_display_terminate(wm.dpy);
789+	(void)data; BIND_EVENT(time, value, state);
790+	wl_display_terminate(wm.dpy);
791 }
792 
793 void spawn(void* data, uint32_t time, uint32_t value, uint32_t state)
794 {
795-VOID(time, value);
796+	BIND_EVENT(time, value, state);
797 
798-union arg* a = data;
799-char* const* cmd = (char* const*)a->v;
800+	pid_t pid = fork();
801+	if (pid == 0) {
802+		setsid();
803+		if (fork() == 0) {
804+			union arg* a = data;
805+			char* const* cmd = (char* const*)a->v;
806 
807-if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
808-return;
809-
810-if (fork() == 0) {
811-execvp(cmd[0], cmd);
812-_exit(127);
813-}
814+			execvp(cmd[0], cmd);
815+			_exit(127);
816+		}
817+		_exit(0);
818+	} else if (pid > 0) {
819+		waitpid(pid, NULL, 0);
820+	}
821 }
822 
823 void workspace_goto(void* data, uint32_t time, uint32_t value, uint32_t state)
824 {
825-VOID(time, value);
826-
827-union arg* a = data;
828-struct client* c;
829+	union arg* a = data;
830+	BIND_EVENT(time, value, state);
831 
832-if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
833-return;
834+	if (a->ui < 1 || a->ui > 9 || a->ui == wm.ws) return;
835 
836-if (a->ui < 1 || a->ui > 9 || a->ui == wm.ws)
837-return;
838+	wm.ws = a->ui;
839+	sync_window_visibility();
840 
841-wm.ws = a->ui;
842-sync_window_visibility();
843-
844-c = first_client(wm.sel_screen);
845-if (!c)
846-c = first_client(NULL);
847-focus(c);
848+	focus(get_focus_candidate(wm.sel_screen));
849 }
850 
851 void workspace_moveto(void* data, uint32_t time, uint32_t value, uint32_t state)
852 {
853-VOID(time, value);
854-
855-union arg* a = data;
856-struct client* c;
857-struct client* next;
858-
859-if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
860-return;
861-
862-if (!wm.sel_client)
863-return;
864-
865-if (a->ui < 1 || a->ui > 9)
866-return;
867+	BIND_ACTION(data, time, value, state);
868+	if (a->ui < 1 || a->ui > 9 || wm.sel_client->ws == a->ui) return;
869 
870-c = wm.sel_client;
871-if (c->ws == a->ui)
872-return;
873+	struct client* c = wm.sel_client;
874+	c->ws = a->ui;
875 
876-c->ws = a->ui;
877-if (c->ws == wm.ws)
878-swc_window_show(c->win);
879-else
880-swc_window_hide(c->win);
881+	if (c->ws == wm.ws)
882+		swc_window_show(c->win);
883+	else
884+		swc_window_hide(c->win);
885 
886-next = first_client(wm.sel_screen);
887-if (!next)
888-next = first_client(NULL);
889-focus(next);
890+	focus(get_focus_candidate(wm.sel_screen));
891 }
892 
893 int main(void)
894 {
895-setup();
896-wl_display_run(wm.dpy);
897-swc_finalize();
898-wl_display_destroy(wm.dpy);
899-return EXIT_SUCCESS;
900+	setup();
901+	wl_display_run(wm.dpy);
902+	swc_finalize();
903+	wl_display_destroy(wm.dpy);
904+	return EXIT_SUCCESS;
905 }