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