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 }