5 #include "framerender.h"
13 Action *action_new(void (*func)(union ActionData *data))
15 Action *a = g_new0(Action, 1);
18 /* deal with pointers */
19 if (func == action_execute)
20 a->data.execute.path = NULL;
25 void action_free(Action *a)
27 if (a == NULL) return;
29 /* deal with pointers */
30 if (a->func == action_execute || a->func == action_restart)
31 g_free(a->data.execute.path);
36 Action *action_from_string(char *name)
39 if (!g_ascii_strcasecmp(name, "execute")) {
40 a = action_new(action_execute);
41 } else if (!g_ascii_strcasecmp(name, "focus")) {
42 a = action_new(action_focus);
43 } else if (!g_ascii_strcasecmp(name, "unfocus")) {
44 a = action_new(action_unfocus);
45 } else if (!g_ascii_strcasecmp(name, "iconify")) {
46 a = action_new(action_iconify);
47 } else if (!g_ascii_strcasecmp(name, "raise")) {
48 a = action_new(action_raise);
49 } else if (!g_ascii_strcasecmp(name, "lower")) {
50 a = action_new(action_lower);
51 } else if (!g_ascii_strcasecmp(name, "focusraise")) {
52 a = action_new(action_focusraise);
53 } else if (!g_ascii_strcasecmp(name, "close")) {
54 a = action_new(action_close);
55 } else if (!g_ascii_strcasecmp(name, "kill")) {
56 a = action_new(action_kill);
57 } else if (!g_ascii_strcasecmp(name, "shadelower")) {
58 a = action_new(action_shadelower);
59 } else if (!g_ascii_strcasecmp(name, "unshaderaise")) {
60 a = action_new(action_unshaderaise);
61 } else if (!g_ascii_strcasecmp(name, "shade")) {
62 a = action_new(action_shade);
63 } else if (!g_ascii_strcasecmp(name, "unshade")) {
64 a = action_new(action_unshade);
65 } else if (!g_ascii_strcasecmp(name, "toggleshade")) {
66 a = action_new(action_toggle_shade);
67 } else if (!g_ascii_strcasecmp(name, "toggleomnipresent")) {
68 a = action_new(action_toggle_omnipresent);
69 } else if (!g_ascii_strcasecmp(name, "moverelativehorz")) {
70 a = action_new(action_move_relative_horz);
71 } else if (!g_ascii_strcasecmp(name, "moverelativevert")) {
72 a = action_new(action_move_relative_vert);
73 } else if (!g_ascii_strcasecmp(name, "resizerelativehorz")) {
74 a = action_new(action_resize_relative_horz);
75 } else if (!g_ascii_strcasecmp(name, "resizerelativevert")) {
76 a = action_new(action_resize_relative_vert);
77 } else if (!g_ascii_strcasecmp(name, "maximizefull")) {
78 a = action_new(action_maximize_full);
79 } else if (!g_ascii_strcasecmp(name, "unmaximizefull")) {
80 a = action_new(action_unmaximize_full);
81 } else if (!g_ascii_strcasecmp(name, "togglemaximizefull")) {
82 a = action_new(action_toggle_maximize_full);
83 } else if (!g_ascii_strcasecmp(name, "maximizehorz")) {
84 a = action_new(action_maximize_horz);
85 } else if (!g_ascii_strcasecmp(name, "unmaximizehorz")) {
86 a = action_new(action_unmaximize_horz);
87 } else if (!g_ascii_strcasecmp(name, "togglemaximizehorz")) {
88 a = action_new(action_toggle_maximize_horz);
89 } else if (!g_ascii_strcasecmp(name, "maximizevert")) {
90 a = action_new(action_maximize_vert);
91 } else if (!g_ascii_strcasecmp(name, "unmaximizevert")) {
92 a = action_new(action_unmaximize_vert);
93 } else if (!g_ascii_strcasecmp(name, "togglemaximizevert")) {
94 a = action_new(action_toggle_maximize_vert);
95 } else if (!g_ascii_strcasecmp(name, "sendtodesktop")) {
96 a = action_new(action_send_to_desktop);
97 a->data.sendto.follow = TRUE;
98 } else if (!g_ascii_strcasecmp(name, "sendtonextdesktop")) {
99 a = action_new(action_send_to_next_desktop);
100 a->data.sendtonextprev.wrap = FALSE;
101 a->data.sendtonextprev.follow = TRUE;
102 } else if (!g_ascii_strcasecmp(name, "sendtonextdesktopwrap")) {
103 a = action_new(action_send_to_next_desktop);
104 a->data.sendtonextprev.wrap = TRUE;
105 a->data.sendtonextprev.follow = TRUE;
106 } else if (!g_ascii_strcasecmp(name, "sendtopreviousdesktop")) {
107 a = action_new(action_send_to_previous_desktop);
108 a->data.sendtonextprev.wrap = FALSE;
109 a->data.sendtonextprev.follow = TRUE;
110 } else if (!g_ascii_strcasecmp(name, "sendtopreviousdesktopwrap")) {
111 a = action_new(action_send_to_previous_desktop);
112 a->data.sendtonextprev.wrap = TRUE;
113 a->data.sendtonextprev.follow = TRUE;
114 } else if (!g_ascii_strcasecmp(name, "desktop")) {
115 a = action_new(action_desktop);
116 } else if (!g_ascii_strcasecmp(name, "nextdesktop")) {
117 a = action_new(action_next_desktop);
118 a->data.nextprevdesktop.wrap = FALSE;
119 } else if (!g_ascii_strcasecmp(name, "nextdesktopwrap")) {
120 a = action_new(action_next_desktop);
121 a->data.nextprevdesktop.wrap = TRUE;
122 } else if (!g_ascii_strcasecmp(name, "previousdesktop")) {
123 a = action_new(action_previous_desktop);
124 a->data.nextprevdesktop.wrap = FALSE;
125 } else if (!g_ascii_strcasecmp(name, "previousdesktopwrap")) {
126 a = action_new(action_previous_desktop);
127 a->data.nextprevdesktop.wrap = TRUE;
128 } else if (!g_ascii_strcasecmp(name, "nextdesktopcolumn")) {
129 a = action_new(action_next_desktop_column);
130 a->data.nextprevdesktop.wrap = FALSE;
131 } else if (!g_ascii_strcasecmp(name, "nextdesktopcolumnwrap")) {
132 a = action_new(action_next_desktop_column);
133 a->data.nextprevdesktop.wrap = TRUE;
134 } else if (!g_ascii_strcasecmp(name, "previousdesktopcolumn")) {
135 a = action_new(action_previous_desktop_column);
136 a->data.nextprevdesktop.wrap = FALSE;
137 } else if (!g_ascii_strcasecmp(name, "previousdesktopcolumnwrap")) {
138 a = action_new(action_previous_desktop_column);
139 a->data.nextprevdesktop.wrap = TRUE;
140 } else if (!g_ascii_strcasecmp(name, "nextdesktoprow")) {
141 a = action_new(action_next_desktop_row);
142 a->data.nextprevdesktop.wrap = FALSE;
143 } else if (!g_ascii_strcasecmp(name, "nextdesktoprowwrap")) {
144 a = action_new(action_next_desktop_row);
145 a->data.nextprevdesktop.wrap = TRUE;
146 } else if (!g_ascii_strcasecmp(name, "previousdesktoprow")) {
147 a = action_new(action_previous_desktop_row);
148 a->data.nextprevdesktop.wrap = FALSE;
149 } else if (!g_ascii_strcasecmp(name, "previousdesktoprowwrap")) {
150 a = action_new(action_previous_desktop_row);
151 a->data.nextprevdesktop.wrap = TRUE;
152 } else if (!g_ascii_strcasecmp(name, "toggledecorations")) {
153 a = action_new(action_toggle_decorations);
154 } else if (!g_ascii_strcasecmp(name, "move")) {
155 a = action_new(action_move);
156 } else if (!g_ascii_strcasecmp(name, "resize")) {
157 a = action_new(action_resize);
158 } else if (!g_ascii_strcasecmp(name, "restart")) {
159 a = action_new(action_restart);
160 } else if (!g_ascii_strcasecmp(name, "exit")) {
161 a = action_new(action_exit);
162 } else if (!g_ascii_strcasecmp(name, "showmenu")) {
163 a = action_new(action_showmenu);
164 } else if (!g_ascii_strcasecmp(name, "nextwindowlinear")) {
165 a = action_new(action_cycle_windows);
166 a->data.cycle.linear = TRUE;
167 a->data.cycle.forward = TRUE;
168 } else if (!g_ascii_strcasecmp(name, "previouswindowlinear")) {
169 a = action_new(action_cycle_windows);
170 a->data.cycle.linear = TRUE;
171 a->data.cycle.forward = FALSE;
172 } else if (!g_ascii_strcasecmp(name, "nextwindow")) {
173 a = action_new(action_cycle_windows);
174 a->data.cycle.linear = FALSE;
175 a->data.cycle.forward = TRUE;
176 } else if (!g_ascii_strcasecmp(name, "previouswindow")) {
177 a = action_new(action_cycle_windows);
178 a->data.cycle.linear = FALSE;
179 a->data.cycle.forward = FALSE;
185 void action_execute(union ActionData *data)
188 if (data->execute.path)
189 if (!g_spawn_command_line_async(data->execute.path, &e)) {
190 g_warning("failed to execute '%s': %s",
191 data->execute.path, e->message);
195 void action_focus(union ActionData *data)
198 client_focus(data->client.c);
201 void action_unfocus (union ActionData *data)
204 client_unfocus(data->client.c);
207 void action_iconify(union ActionData *data)
210 client_iconify(data->client.c, TRUE, TRUE);
213 void action_focusraise(union ActionData *data)
215 if (data->client.c) {
216 client_focus(data->client.c);
217 stacking_raise(data->client.c);
221 void action_raise(union ActionData *data)
224 stacking_raise(data->client.c);
227 void action_unshaderaise(union ActionData *data)
229 if (data->client.c) {
230 if (data->client.c->shaded)
231 client_shade(data->client.c, FALSE);
233 stacking_raise(data->client.c);
237 void action_shadelower(union ActionData *data)
239 if (data->client.c) {
240 if (data->client.c->shaded)
241 stacking_lower(data->client.c);
243 client_shade(data->client.c, TRUE);
247 void action_lower(union ActionData *data)
250 stacking_lower(data->client.c);
253 void action_close(union ActionData *data)
256 client_close(data->client.c);
259 void action_kill(union ActionData *data)
262 client_kill(data->client.c);
265 void action_shade(union ActionData *data)
268 client_shade(data->client.c, TRUE);
271 void action_unshade(union ActionData *data)
274 client_shade(data->client.c, FALSE);
277 void action_toggle_shade(union ActionData *data)
280 client_shade(data->client.c, !data->client.c->shaded);
283 void action_toggle_omnipresent(union ActionData *data)
286 client_set_desktop(data->client.c,
287 data->client.c->desktop == DESKTOP_ALL ?
288 screen_desktop : DESKTOP_ALL, FALSE);
291 void action_move_relative_horz(union ActionData *data)
293 Client *c = data->relative.c;
295 client_configure(c, Corner_TopLeft,
296 c->area.x + data->relative.delta, c->area.y,
297 c->area.width, c->area.height, TRUE, TRUE);
300 void action_move_relative_vert(union ActionData *data)
302 Client *c = data->relative.c;
304 client_configure(c, Corner_TopLeft,
305 c->area.x, c->area.y + data->relative.delta,
306 c->area.width, c->area.height, TRUE, TRUE);
309 void action_resize_relative_horz(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 + data->relative.delta,
315 c->area.height, TRUE, TRUE);
318 void action_resize_relative_vert(union ActionData *data)
320 Client *c = data->relative.c;
322 client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
323 c->area.width, c->area.height + data->relative.delta,
327 void action_maximize_full(union ActionData *data)
330 client_maximize(data->client.c, TRUE, 0, TRUE);
333 void action_unmaximize_full(union ActionData *data)
336 client_maximize(data->client.c, FALSE, 0, TRUE);
339 void action_toggle_maximize_full(union ActionData *data)
342 client_maximize(data->client.c,
343 !(data->client.c->max_horz ||
344 data->client.c->max_vert),
348 void action_maximize_horz(union ActionData *data)
351 client_maximize(data->client.c, TRUE, 1, TRUE);
354 void action_unmaximize_horz(union ActionData *data)
357 client_maximize(data->client.c, FALSE, 1, TRUE);
360 void action_toggle_maximize_horz(union ActionData *data)
363 client_maximize(data->client.c, !data->client.c->max_horz, 1, TRUE);
366 void action_maximize_vert(union ActionData *data)
369 client_maximize(data->client.c, TRUE, 2, TRUE);
372 void action_unmaximize_vert(union ActionData *data)
375 client_maximize(data->client.c, FALSE, 2, TRUE);
378 void action_toggle_maximize_vert(union ActionData *data)
381 client_maximize(data->client.c, !data->client.c->max_vert, 2, TRUE);
384 void action_send_to_desktop(union ActionData *data)
386 if (data->sendto.c) {
387 if (data->sendto.desk < screen_num_desktops ||
388 data->sendto.desk == DESKTOP_ALL) {
389 client_set_desktop(data->desktop.c,
390 data->sendto.desk, data->sendto.follow);
391 if (data->sendto.follow) screen_set_desktop(data->sendto.desk);
396 void action_send_to_next_desktop(union ActionData *data)
400 if (!data->sendtonextprev.c) return;
402 d = screen_desktop + 1;
403 if (d >= screen_num_desktops) {
404 if (!data->sendtonextprev.wrap) return;
407 client_set_desktop(data->sendtonextprev.c, d, data->sendtonextprev.follow);
408 if (data->sendtonextprev.follow) screen_set_desktop(d);
411 void action_send_to_previous_desktop(union ActionData *data)
415 if (!data->sendtonextprev.c) return;
417 d = screen_desktop - 1;
418 if (d >= screen_num_desktops) {
419 if (!data->sendtonextprev.wrap) return;
420 d = screen_num_desktops - 1;
422 client_set_desktop(data->sendtonextprev.c, d, data->sendtonextprev.follow);
423 if (data->sendtonextprev.follow) screen_set_desktop(d);
426 void action_desktop(union ActionData *data)
428 if (data->desktop.desk < screen_num_desktops ||
429 data->desktop.desk == DESKTOP_ALL)
430 screen_set_desktop(data->desktop.desk);
433 void action_next_desktop(union ActionData *data)
437 d = screen_desktop + 1;
438 if (d >= screen_num_desktops) {
439 if (!data->nextprevdesktop.wrap) return;
442 screen_set_desktop(d);
445 void action_previous_desktop(union ActionData *data)
449 d = screen_desktop - 1;
450 if (d >= screen_num_desktops) {
451 if (!data->nextprevdesktop.wrap) return;
452 d = screen_num_desktops - 1;
454 screen_set_desktop(d);
457 static void cur_row_col(guint *r, guint *c)
459 switch (screen_desktop_layout.orientation) {
460 case Orientation_Horz:
461 switch (screen_desktop_layout.start_corner) {
463 *r = screen_desktop / screen_desktop_layout.columns;
464 *c = screen_desktop % screen_desktop_layout.columns;
466 case Corner_BottomLeft:
467 *r = screen_desktop_layout.rows - 1 -
468 screen_desktop / screen_desktop_layout.columns;
469 *c = screen_desktop % screen_desktop_layout.columns;
471 case Corner_TopRight:
472 *r = screen_desktop / screen_desktop_layout.columns;
473 *c = screen_desktop_layout.columns - 1 -
474 screen_desktop % screen_desktop_layout.columns;
476 case Corner_BottomRight:
477 *r = screen_desktop_layout.rows - 1 -
478 screen_desktop / screen_desktop_layout.columns;
479 *c = screen_desktop_layout.columns - 1 -
480 screen_desktop % screen_desktop_layout.columns;
484 case Orientation_Vert:
485 switch (screen_desktop_layout.start_corner) {
487 *r = screen_desktop % screen_desktop_layout.rows;
488 *c = screen_desktop / screen_desktop_layout.rows;
490 case Corner_BottomLeft:
491 *r = screen_desktop_layout.rows - 1 -
492 screen_desktop % screen_desktop_layout.rows;
493 *c = screen_desktop / screen_desktop_layout.rows;
495 case Corner_TopRight:
496 *r = screen_desktop % screen_desktop_layout.rows;
497 *c = screen_desktop_layout.columns - 1 -
498 screen_desktop / screen_desktop_layout.rows;
500 case Corner_BottomRight:
501 *r = screen_desktop_layout.rows - 1 -
502 screen_desktop % screen_desktop_layout.rows;
503 *c = screen_desktop_layout.columns - 1 -
504 screen_desktop / screen_desktop_layout.rows;
511 static guint translate_row_col(guint r, guint c)
513 switch (screen_desktop_layout.orientation) {
514 case Orientation_Horz:
515 switch (screen_desktop_layout.start_corner) {
517 return r * screen_desktop_layout.columns + c;
518 case Corner_BottomLeft:
519 return (screen_desktop_layout.rows - 1 - r) *
520 screen_desktop_layout.columns + c;
521 case Corner_TopRight:
522 return r * screen_desktop_layout.columns +
523 (screen_desktop_layout.columns - 1 - c);
524 case Corner_BottomRight:
525 return (screen_desktop_layout.rows - 1 - r) *
526 screen_desktop_layout.columns +
527 (screen_desktop_layout.columns - 1 - c);
529 case Orientation_Vert:
530 switch (screen_desktop_layout.start_corner) {
532 return c * screen_desktop_layout.rows + r;
533 case Corner_BottomLeft:
534 return c * screen_desktop_layout.rows +
535 (screen_desktop_layout.rows - 1 - r);
536 case Corner_TopRight:
537 return (screen_desktop_layout.columns - 1 - c) *
538 screen_desktop_layout.rows + r;
539 case Corner_BottomRight:
540 return (screen_desktop_layout.columns - 1 - c) *
541 screen_desktop_layout.rows +
542 (screen_desktop_layout.rows - 1 - r);
545 g_assert_not_reached();
549 void action_next_desktop_column(union ActionData *data)
555 d = translate_row_col(r, c);
556 if (d >= screen_num_desktops) {
557 if (!data->nextprevdesktop.wrap) return;
560 if (d >= screen_num_desktops)
562 d = translate_row_col(r, c);
563 if (d < screen_num_desktops)
564 screen_set_desktop(d);
567 void action_previous_desktop_column(union ActionData *data)
573 d = translate_row_col(r, c);
574 if (d >= screen_num_desktops) {
575 if (!data->nextprevdesktop.wrap) return;
576 c = screen_desktop_layout.columns - 1;
578 if (d >= screen_num_desktops)
580 d = translate_row_col(r, c);
581 if (d < screen_num_desktops)
582 screen_set_desktop(d);
585 void action_next_desktop_row(union ActionData *data)
591 d = translate_row_col(r, c);
592 if (d >= screen_num_desktops) {
593 if (!data->nextprevdesktop.wrap) return;
596 if (d >= screen_num_desktops)
598 d = translate_row_col(r, c);
599 if (d < screen_num_desktops)
600 screen_set_desktop(d);
603 void action_previous_desktop_row(union ActionData *data)
609 d = translate_row_col(r, c);
610 if (d >= screen_num_desktops) {
611 if (!data->nextprevdesktop.wrap) return;
612 c = screen_desktop_layout.rows - 1;
614 if (d >= screen_num_desktops)
616 d = translate_row_col(r, c);
617 if (d < screen_num_desktops)
618 screen_set_desktop(d);
621 void action_toggle_decorations(union ActionData *data)
623 Client *c = data->client.c;;
627 c->disabled_decorations = c->disabled_decorations ? 0 : ~0;
628 client_setup_decor_and_functions(c);
631 static void popup_coords(char *format, int a, int b, gboolean hide)
633 XSetWindowAttributes attrib;
634 static Window coords = None;
636 if (coords == None) {
637 attrib.override_redirect = TRUE;
638 coords = XCreateWindow(ob_display, ob_root,
639 0, 0, 1, 1, 0, render_depth, InputOutput,
640 render_visual, CWOverrideRedirect, &attrib);
641 g_assert(coords != None);
645 XUnmapWindow(ob_display, coords);
650 text = g_strdup_printf(format, a, b);
651 framerender_size_popup_label(text, &s);
652 XMoveResizeWindow(ob_display, coords,
653 10, 10, s.width, s.height);
654 framerender_popup_label(coords, &s, text);
657 XMapWindow(ob_display, coords);
661 void action_move(union ActionData *data)
663 Client *c = data->move.c;
664 int x = data->move.x;
665 int y = data->move.y;
667 if (!c || !client_normal(c)) return;
669 dispatch_move(c, &x, &y);
671 popup_coords("X: %d Y: %d", x, y, data->move.final);
673 frame_frame_gravity(c->frame, &x, &y); /* get where the client should be */
674 client_configure(c, Corner_TopLeft, x, y, c->area.width, c->area.height,
675 TRUE, data->move.final);
678 void action_resize(union ActionData *data)
680 Client *c = data->resize.c;
681 int w = data->resize.x;
682 int h = data->resize.y;
684 if (!c || c->shaded || !client_normal(c)) return;
686 dispatch_resize(c, &w, &h, data->resize.corner);
688 w -= c->frame->size.left + c->frame->size.right;
689 h -= c->frame->size.top + c->frame->size.bottom;
691 client_configure(c, data->resize.corner, c->area.x, c->area.y, w, h,
692 TRUE, data->resize.final);
694 popup_coords("W: %d H: %d", c->logical_size.width,
695 c->logical_size.height, data->move.final);
698 void action_restart(union ActionData *data)
700 ob_restart_path = data->execute.path;
701 ob_shutdown = ob_restart = TRUE;
704 void action_exit(union ActionData *data)
709 void action_showmenu(union ActionData *data)
711 g_message(__FUNCTION__);
714 static void popup_cycle(Client *c, gboolean hide)
716 XSetWindowAttributes attrib;
717 static Window coords = None;
719 if (coords == None) {
720 attrib.override_redirect = TRUE;
721 coords = XCreateWindow(ob_display, ob_root,
722 0, 0, 1, 1, 0, render_depth, InputOutput,
723 render_visual, CWOverrideRedirect, &attrib);
724 g_assert(coords != None);
728 XUnmapWindow(ob_display, coords);
733 a = screen_area(c->desktop);
735 framerender_size_popup_label(c->title, &s);
736 XMoveResizeWindow(ob_display, coords,
737 a->x + (a->width - s.width) / 2,
738 a->y + (a->height - s.height) / 2,
740 framerender_popup_label(coords, &s, c->title);
742 XMapWindow(ob_display, coords);
746 void action_cycle_windows(union ActionData *data)
750 c = focus_cycle(data->cycle.forward, data->cycle.linear, data->cycle.final,
752 popup_cycle(c, !c || data->cycle.final || data->cycle.cancel);