12 Action *action_new(void (*func)(union ActionData *data))
14 Action *a = g_new0(Action, 1);
17 /* deal with pointers */
18 if (func == action_execute)
19 a->data.execute.path = NULL;
24 void action_free(Action *a)
26 if (a == NULL) return;
28 /* deal with pointers */
29 if (a->func == action_execute || a->func == action_restart)
30 g_free(a->data.execute.path);
35 Action *action_from_string(char *name)
38 if (!g_ascii_strcasecmp(name, "execute")) {
39 a = action_new(action_execute);
40 } else if (!g_ascii_strcasecmp(name, "focus")) {
41 a = action_new(action_focus);
42 } else if (!g_ascii_strcasecmp(name, "unfocus")) {
43 a = action_new(action_unfocus);
44 } else if (!g_ascii_strcasecmp(name, "iconify")) {
45 a = action_new(action_iconify);
46 } else if (!g_ascii_strcasecmp(name, "raise")) {
47 a = action_new(action_raise);
48 } else if (!g_ascii_strcasecmp(name, "lower")) {
49 a = action_new(action_lower);
50 } else if (!g_ascii_strcasecmp(name, "focusraise")) {
51 a = action_new(action_focusraise);
52 } else if (!g_ascii_strcasecmp(name, "close")) {
53 a = action_new(action_close);
54 } else if (!g_ascii_strcasecmp(name, "kill")) {
55 a = action_new(action_kill);
56 } else if (!g_ascii_strcasecmp(name, "shadelower")) {
57 a = action_new(action_shadelower);
58 } else if (!g_ascii_strcasecmp(name, "unshaderaise")) {
59 a = action_new(action_unshaderaise);
60 } else if (!g_ascii_strcasecmp(name, "shade")) {
61 a = action_new(action_shade);
62 } else if (!g_ascii_strcasecmp(name, "unshade")) {
63 a = action_new(action_unshade);
64 } else if (!g_ascii_strcasecmp(name, "toggleshade")) {
65 a = action_new(action_toggle_shade);
66 } else if (!g_ascii_strcasecmp(name, "toggleomnipresent")) {
67 a = action_new(action_toggle_omnipresent);
68 } else if (!g_ascii_strcasecmp(name, "moverelativehorz")) {
69 a = action_new(action_move_relative_horz);
70 } else if (!g_ascii_strcasecmp(name, "moverelativevert")) {
71 a = action_new(action_move_relative_vert);
72 } else if (!g_ascii_strcasecmp(name, "resizerelativehorz")) {
73 a = action_new(action_resize_relative_horz);
74 } else if (!g_ascii_strcasecmp(name, "resizerelativevert")) {
75 a = action_new(action_resize_relative_vert);
76 } else if (!g_ascii_strcasecmp(name, "maximizefull")) {
77 a = action_new(action_maximize_full);
78 } else if (!g_ascii_strcasecmp(name, "unmaximizefull")) {
79 a = action_new(action_unmaximize_full);
80 } else if (!g_ascii_strcasecmp(name, "togglemaximizefull")) {
81 a = action_new(action_toggle_maximize_full);
82 } else if (!g_ascii_strcasecmp(name, "maximizehorz")) {
83 a = action_new(action_maximize_horz);
84 } else if (!g_ascii_strcasecmp(name, "unmaximizehorz")) {
85 a = action_new(action_unmaximize_horz);
86 } else if (!g_ascii_strcasecmp(name, "togglemaximizehorz")) {
87 a = action_new(action_toggle_maximize_horz);
88 } else if (!g_ascii_strcasecmp(name, "maximizevert")) {
89 a = action_new(action_maximize_vert);
90 } else if (!g_ascii_strcasecmp(name, "unmaximizevert")) {
91 a = action_new(action_unmaximize_vert);
92 } else if (!g_ascii_strcasecmp(name, "togglemaximizevert")) {
93 a = action_new(action_toggle_maximize_vert);
94 } else if (!g_ascii_strcasecmp(name, "sendtodesktop")) {
95 a = action_new(action_send_to_desktop);
96 a->data.sendto.follow = TRUE;
97 } else if (!g_ascii_strcasecmp(name, "sendtonextdesktop")) {
98 a = action_new(action_send_to_next_desktop);
99 a->data.sendtonextprev.wrap = FALSE;
100 a->data.sendtonextprev.follow = TRUE;
101 } else if (!g_ascii_strcasecmp(name, "sendtonextdesktopwrap")) {
102 a = action_new(action_send_to_next_desktop);
103 a->data.sendtonextprev.wrap = TRUE;
104 a->data.sendtonextprev.follow = TRUE;
105 } else if (!g_ascii_strcasecmp(name, "sendtopreviousdesktop")) {
106 a = action_new(action_send_to_previous_desktop);
107 a->data.sendtonextprev.wrap = FALSE;
108 a->data.sendtonextprev.follow = TRUE;
109 } else if (!g_ascii_strcasecmp(name, "sendtopreviousdesktopwrap")) {
110 a = action_new(action_send_to_previous_desktop);
111 a->data.sendtonextprev.wrap = TRUE;
112 a->data.sendtonextprev.follow = TRUE;
113 } else if (!g_ascii_strcasecmp(name, "desktop")) {
114 a = action_new(action_desktop);
115 } else if (!g_ascii_strcasecmp(name, "nextdesktop")) {
116 a = action_new(action_next_desktop);
117 a->data.nextprevdesktop.wrap = FALSE;
118 } else if (!g_ascii_strcasecmp(name, "nextdesktopwrap")) {
119 a = action_new(action_next_desktop);
120 a->data.nextprevdesktop.wrap = TRUE;
121 } else if (!g_ascii_strcasecmp(name, "previousdesktop")) {
122 a = action_new(action_previous_desktop);
123 a->data.nextprevdesktop.wrap = FALSE;
124 } else if (!g_ascii_strcasecmp(name, "previousdesktopwrap")) {
125 a = action_new(action_previous_desktop);
126 a->data.nextprevdesktop.wrap = TRUE;
127 } else if (!g_ascii_strcasecmp(name, "nextdesktopcolumn")) {
128 a = action_new(action_next_desktop_column);
129 a->data.nextprevdesktop.wrap = FALSE;
130 } else if (!g_ascii_strcasecmp(name, "nextdesktopcolumnwrap")) {
131 a = action_new(action_next_desktop_column);
132 a->data.nextprevdesktop.wrap = TRUE;
133 } else if (!g_ascii_strcasecmp(name, "previousdesktopcolumn")) {
134 a = action_new(action_previous_desktop_column);
135 a->data.nextprevdesktop.wrap = FALSE;
136 } else if (!g_ascii_strcasecmp(name, "previousdesktopcolumnwrap")) {
137 a = action_new(action_previous_desktop_column);
138 a->data.nextprevdesktop.wrap = TRUE;
139 } else if (!g_ascii_strcasecmp(name, "nextdesktoprow")) {
140 a = action_new(action_next_desktop_row);
141 a->data.nextprevdesktop.wrap = FALSE;
142 } else if (!g_ascii_strcasecmp(name, "nextdesktoprowwrap")) {
143 a = action_new(action_next_desktop_row);
144 a->data.nextprevdesktop.wrap = TRUE;
145 } else if (!g_ascii_strcasecmp(name, "previousdesktoprow")) {
146 a = action_new(action_previous_desktop_row);
147 a->data.nextprevdesktop.wrap = FALSE;
148 } else if (!g_ascii_strcasecmp(name, "previousdesktoprowwrap")) {
149 a = action_new(action_previous_desktop_row);
150 a->data.nextprevdesktop.wrap = TRUE;
151 } else if (!g_ascii_strcasecmp(name, "toggledecorations")) {
152 a = action_new(action_toggle_decorations);
153 } else if (!g_ascii_strcasecmp(name, "move")) {
154 a = action_new(action_move);
155 } else if (!g_ascii_strcasecmp(name, "resize")) {
156 a = action_new(action_resize);
157 } else if (!g_ascii_strcasecmp(name, "restart")) {
158 a = action_new(action_restart);
159 } else if (!g_ascii_strcasecmp(name, "exit")) {
160 a = action_new(action_exit);
161 } else if (!g_ascii_strcasecmp(name, "showmenu")) {
162 a = action_new(action_showmenu);
163 } else if (!g_ascii_strcasecmp(name, "nextwindowlinear")) {
164 a = action_new(action_cycle_windows);
165 a->data.cycle.linear = TRUE;
166 a->data.cycle.forward = TRUE;
167 } else if (!g_ascii_strcasecmp(name, "previouswindowlinear")) {
168 a = action_new(action_cycle_windows);
169 a->data.cycle.linear = TRUE;
170 a->data.cycle.forward = FALSE;
176 void action_execute(union ActionData *data)
179 if (data->execute.path)
180 if (!g_spawn_command_line_async(data->execute.path, &e)) {
181 g_warning("failed to execute '%s': %s",
182 data->execute.path, e->message);
186 void action_focus(union ActionData *data)
189 client_focus(data->client.c);
192 void action_unfocus (union ActionData *data)
195 client_unfocus(data->client.c);
198 void action_iconify(union ActionData *data)
201 client_iconify(data->client.c, TRUE, TRUE);
204 void action_focusraise(union ActionData *data)
206 if (data->client.c) {
207 client_focus(data->client.c);
208 stacking_raise(data->client.c);
212 void action_raise(union ActionData *data)
215 stacking_raise(data->client.c);
218 void action_unshaderaise(union ActionData *data)
220 if (data->client.c) {
221 if (data->client.c->shaded)
222 client_shade(data->client.c, FALSE);
224 stacking_raise(data->client.c);
228 void action_shadelower(union ActionData *data)
230 if (data->client.c) {
231 if (data->client.c->shaded)
232 stacking_lower(data->client.c);
234 client_shade(data->client.c, TRUE);
238 void action_lower(union ActionData *data)
241 stacking_lower(data->client.c);
244 void action_close(union ActionData *data)
247 client_close(data->client.c);
250 void action_kill(union ActionData *data)
253 client_kill(data->client.c);
256 void action_shade(union ActionData *data)
259 client_shade(data->client.c, TRUE);
262 void action_unshade(union ActionData *data)
265 client_shade(data->client.c, FALSE);
268 void action_toggle_shade(union ActionData *data)
271 client_shade(data->client.c, !data->client.c->shaded);
274 void action_toggle_omnipresent(union ActionData *data)
277 client_set_desktop(data->client.c,
278 data->client.c->desktop == DESKTOP_ALL ?
279 screen_desktop : DESKTOP_ALL, FALSE);
282 void action_move_relative_horz(union ActionData *data)
284 Client *c = data->relative.c;
286 client_configure(c, Corner_TopLeft,
287 c->area.x + data->relative.delta, c->area.y,
288 c->area.width, c->area.height, TRUE, TRUE);
291 void action_move_relative_vert(union ActionData *data)
293 Client *c = data->relative.c;
295 client_configure(c, Corner_TopLeft,
296 c->area.x, c->area.y + data->relative.delta,
297 c->area.width, c->area.height, TRUE, TRUE);
300 void action_resize_relative_horz(union ActionData *data)
302 Client *c = data->relative.c;
304 client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
305 c->area.width + data->relative.delta,
306 c->area.height, TRUE, TRUE);
309 void action_resize_relative_vert(union ActionData *data)
311 Client *c = data->relative.c;
313 client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
314 c->area.width, c->area.height + data->relative.delta,
318 void action_maximize_full(union ActionData *data)
321 client_maximize(data->client.c, TRUE, 0, TRUE);
324 void action_unmaximize_full(union ActionData *data)
327 client_maximize(data->client.c, FALSE, 0, TRUE);
330 void action_toggle_maximize_full(union ActionData *data)
333 client_maximize(data->client.c,
334 !(data->client.c->max_horz ||
335 data->client.c->max_vert),
339 void action_maximize_horz(union ActionData *data)
342 client_maximize(data->client.c, TRUE, 1, TRUE);
345 void action_unmaximize_horz(union ActionData *data)
348 client_maximize(data->client.c, FALSE, 1, TRUE);
351 void action_toggle_maximize_horz(union ActionData *data)
354 client_maximize(data->client.c, !data->client.c->max_horz, 1, TRUE);
357 void action_maximize_vert(union ActionData *data)
360 client_maximize(data->client.c, TRUE, 2, TRUE);
363 void action_unmaximize_vert(union ActionData *data)
366 client_maximize(data->client.c, FALSE, 2, TRUE);
369 void action_toggle_maximize_vert(union ActionData *data)
372 client_maximize(data->client.c, !data->client.c->max_vert, 2, TRUE);
375 void action_send_to_desktop(union ActionData *data)
377 if (data->sendto.c) {
378 if (data->sendto.desk < screen_num_desktops ||
379 data->sendto.desk == DESKTOP_ALL) {
380 client_set_desktop(data->desktop.c,
381 data->sendto.desk, data->sendto.follow);
382 if (data->sendto.follow) screen_set_desktop(data->sendto.desk);
387 void action_send_to_next_desktop(union ActionData *data)
391 if (!data->sendtonextprev.c) return;
393 d = screen_desktop + 1;
394 if (d >= screen_num_desktops) {
395 if (!data->sendtonextprev.wrap) return;
398 client_set_desktop(data->sendtonextprev.c, d, data->sendtonextprev.follow);
399 if (data->sendtonextprev.follow) screen_set_desktop(d);
402 void action_send_to_previous_desktop(union ActionData *data)
406 if (!data->sendtonextprev.c) return;
408 d = screen_desktop - 1;
409 if (d >= screen_num_desktops) {
410 if (!data->sendtonextprev.wrap) return;
411 d = screen_num_desktops - 1;
413 client_set_desktop(data->sendtonextprev.c, d, data->sendtonextprev.follow);
414 if (data->sendtonextprev.follow) screen_set_desktop(d);
417 void action_desktop(union ActionData *data)
419 if (data->desktop.desk < screen_num_desktops ||
420 data->desktop.desk == DESKTOP_ALL)
421 screen_set_desktop(data->desktop.desk);
424 void action_next_desktop(union ActionData *data)
428 d = screen_desktop + 1;
429 if (d >= screen_num_desktops) {
430 if (!data->nextprevdesktop.wrap) return;
433 screen_set_desktop(d);
436 void action_previous_desktop(union ActionData *data)
440 d = screen_desktop - 1;
441 if (d >= screen_num_desktops) {
442 if (!data->nextprevdesktop.wrap) return;
443 d = screen_num_desktops - 1;
445 screen_set_desktop(d);
448 static void cur_row_col(guint *r, guint *c)
450 switch (screen_desktop_layout.orientation) {
451 case Orientation_Horz:
452 switch (screen_desktop_layout.start_corner) {
454 *r = screen_desktop / screen_desktop_layout.columns;
455 *c = screen_desktop % screen_desktop_layout.columns;
457 case Corner_BottomLeft:
458 *r = screen_desktop_layout.rows - 1 -
459 screen_desktop / screen_desktop_layout.columns;
460 *c = screen_desktop % screen_desktop_layout.columns;
462 case Corner_TopRight:
463 *r = screen_desktop / screen_desktop_layout.columns;
464 *c = screen_desktop_layout.columns - 1 -
465 screen_desktop % screen_desktop_layout.columns;
467 case Corner_BottomRight:
468 *r = screen_desktop_layout.rows - 1 -
469 screen_desktop / screen_desktop_layout.columns;
470 *c = screen_desktop_layout.columns - 1 -
471 screen_desktop % screen_desktop_layout.columns;
475 case Orientation_Vert:
476 switch (screen_desktop_layout.start_corner) {
478 *r = screen_desktop % screen_desktop_layout.rows;
479 *c = screen_desktop / screen_desktop_layout.rows;
481 case Corner_BottomLeft:
482 *r = screen_desktop_layout.rows - 1 -
483 screen_desktop % screen_desktop_layout.rows;
484 *c = screen_desktop / screen_desktop_layout.rows;
486 case Corner_TopRight:
487 *r = screen_desktop % screen_desktop_layout.rows;
488 *c = screen_desktop_layout.columns - 1 -
489 screen_desktop / screen_desktop_layout.rows;
491 case Corner_BottomRight:
492 *r = screen_desktop_layout.rows - 1 -
493 screen_desktop % screen_desktop_layout.rows;
494 *c = screen_desktop_layout.columns - 1 -
495 screen_desktop / screen_desktop_layout.rows;
502 static guint translate_row_col(guint r, guint c)
504 switch (screen_desktop_layout.orientation) {
505 case Orientation_Horz:
506 switch (screen_desktop_layout.start_corner) {
508 return r * screen_desktop_layout.columns + c;
509 case Corner_BottomLeft:
510 return (screen_desktop_layout.rows - 1 - r) *
511 screen_desktop_layout.columns + c;
512 case Corner_TopRight:
513 return r * screen_desktop_layout.columns +
514 (screen_desktop_layout.columns - 1 - c);
515 case Corner_BottomRight:
516 return (screen_desktop_layout.rows - 1 - r) *
517 screen_desktop_layout.columns +
518 (screen_desktop_layout.columns - 1 - c);
520 case Orientation_Vert:
521 switch (screen_desktop_layout.start_corner) {
523 return c * screen_desktop_layout.rows + r;
524 case Corner_BottomLeft:
525 return c * screen_desktop_layout.rows +
526 (screen_desktop_layout.rows - 1 - r);
527 case Corner_TopRight:
528 return (screen_desktop_layout.columns - 1 - c) *
529 screen_desktop_layout.rows + r;
530 case Corner_BottomRight:
531 return (screen_desktop_layout.columns - 1 - c) *
532 screen_desktop_layout.rows +
533 (screen_desktop_layout.rows - 1 - r);
536 g_assert_not_reached();
540 void action_next_desktop_column(union ActionData *data)
546 d = translate_row_col(r, c);
547 if (d >= screen_num_desktops) {
548 if (!data->nextprevdesktop.wrap) return;
551 if (d >= screen_num_desktops)
553 d = translate_row_col(r, c);
554 if (d < screen_num_desktops)
555 screen_set_desktop(d);
558 void action_previous_desktop_column(union ActionData *data)
564 d = translate_row_col(r, c);
565 if (d >= screen_num_desktops) {
566 if (!data->nextprevdesktop.wrap) return;
567 c = screen_desktop_layout.columns - 1;
569 if (d >= screen_num_desktops)
571 d = translate_row_col(r, c);
572 if (d < screen_num_desktops)
573 screen_set_desktop(d);
576 void action_next_desktop_row(union ActionData *data)
582 d = translate_row_col(r, c);
583 if (d >= screen_num_desktops) {
584 if (!data->nextprevdesktop.wrap) return;
587 if (d >= screen_num_desktops)
589 d = translate_row_col(r, c);
590 if (d < screen_num_desktops)
591 screen_set_desktop(d);
594 void action_previous_desktop_row(union ActionData *data)
600 d = translate_row_col(r, c);
601 if (d >= screen_num_desktops) {
602 if (!data->nextprevdesktop.wrap) return;
603 c = screen_desktop_layout.rows - 1;
605 if (d >= screen_num_desktops)
607 d = translate_row_col(r, c);
608 if (d < screen_num_desktops)
609 screen_set_desktop(d);
612 void action_toggle_decorations(union ActionData *data)
614 Client *c = data->client.c;
615 c->disabled_decorations = c->disabled_decorations ? 0 : ~0;
616 client_setup_decor_and_functions(c);
619 void action_move(union ActionData *data)
621 Client *c = data->move.c;
622 int x = data->move.x;
623 int y = data->move.y;
625 if (!c || !client_normal(c)) return;
627 dispatch_move(c, &x, &y);
629 frame_frame_gravity(c->frame, &x, &y); /* get where the client should be */
630 client_configure(c, Corner_TopLeft, x, y, c->area.width, c->area.height,
631 TRUE, data->move.final);
634 void action_resize(union ActionData *data)
636 Client *c = data->resize.c;
637 int w = data->resize.x;
638 int h = data->resize.y;
640 if (!c || c->shaded || !client_normal(c)) return;
642 dispatch_resize(c, &w, &h, data->resize.corner);
644 w -= c->frame->size.left + c->frame->size.right;
645 h -= c->frame->size.top + c->frame->size.bottom;
647 client_configure(c, data->resize.corner, c->area.x, c->area.y, w, h,
648 TRUE, data->resize.final);
651 void action_restart(union ActionData *data)
653 ob_restart_path = data->execute.path;
654 ob_shutdown = ob_restart = TRUE;
657 void action_exit(union ActionData *data)
662 void action_showmenu(union ActionData *data)
664 g_message(__FUNCTION__);
667 void action_cycle_windows(union ActionData *data)
669 if (data->cycle.linear) {
670 static Client *first = NULL;
671 static Client *t = NULL;
673 if (data->cycle.cancel) {
674 if (first) client_focus(first);
675 } else if (!data->cycle.final) {
679 first = focus_client;
680 start = it = g_list_find(client_list, data->cycle.c);
682 if (data->cycle.forward) {
684 if (it == NULL) it = client_list;
687 if (it == NULL) it = g_list_last(client_list);
689 if (client_focus(it->data)) {
693 } while (it != start);
695 if (t) stacking_raise(t);