11 Action *action_new(void (*func)(union ActionData *data))
13 Action *a = g_new0(Action, 1);
16 /* deal with pointers */
17 if (func == action_execute)
18 a->data.execute.path = NULL;
23 void action_free(Action *a)
25 if (a == NULL) return;
27 /* deal with pointers */
28 if (a->func == action_execute || a->func == action_restart)
29 g_free(a->data.execute.path);
34 Action *action_from_string(char *name)
37 if (!g_ascii_strcasecmp(name, "execute")) {
38 a = action_new(action_execute);
39 } else if (!g_ascii_strcasecmp(name, "focus")) {
40 a = action_new(action_focus);
41 } else if (!g_ascii_strcasecmp(name, "unfocus")) {
42 a = action_new(action_unfocus);
43 } else if (!g_ascii_strcasecmp(name, "iconify")) {
44 a = action_new(action_iconify);
45 } else if (!g_ascii_strcasecmp(name, "raise")) {
46 a = action_new(action_raise);
47 } else if (!g_ascii_strcasecmp(name, "lower")) {
48 a = action_new(action_lower);
49 } else if (!g_ascii_strcasecmp(name, "focusraise")) {
50 a = action_new(action_focusraise);
51 } else if (!g_ascii_strcasecmp(name, "close")) {
52 a = action_new(action_close);
53 } else if (!g_ascii_strcasecmp(name, "kill")) {
54 a = action_new(action_kill);
55 } else if (!g_ascii_strcasecmp(name, "shade")) {
56 a = action_new(action_shade);
57 } else if (!g_ascii_strcasecmp(name, "unshade")) {
58 a = action_new(action_unshade);
59 } else if (!g_ascii_strcasecmp(name, "toggleshade")) {
60 a = action_new(action_toggle_shade);
61 } else if (!g_ascii_strcasecmp(name, "toggleomnipresent")) {
62 a = action_new(action_toggle_omnipresent);
63 } else if (!g_ascii_strcasecmp(name, "moverelativehorz")) {
64 a = action_new(action_move_relative_horz);
65 } else if (!g_ascii_strcasecmp(name, "moverelativevert")) {
66 a = action_new(action_move_relative_vert);
67 } else if (!g_ascii_strcasecmp(name, "resizerelativehorz")) {
68 a = action_new(action_resize_relative_horz);
69 } else if (!g_ascii_strcasecmp(name, "resizerelativevert")) {
70 a = action_new(action_resize_relative_vert);
71 } else if (!g_ascii_strcasecmp(name, "maximizefull")) {
72 a = action_new(action_maximize_full);
73 } else if (!g_ascii_strcasecmp(name, "unmaximizefull")) {
74 a = action_new(action_unmaximize_full);
75 } else if (!g_ascii_strcasecmp(name, "togglemaximizefull")) {
76 a = action_new(action_toggle_maximize_full);
77 } else if (!g_ascii_strcasecmp(name, "maximizehorz")) {
78 a = action_new(action_maximize_horz);
79 } else if (!g_ascii_strcasecmp(name, "unmaximizehorz")) {
80 a = action_new(action_unmaximize_horz);
81 } else if (!g_ascii_strcasecmp(name, "togglemaximizehorz")) {
82 a = action_new(action_toggle_maximize_horz);
83 } else if (!g_ascii_strcasecmp(name, "maximizevert")) {
84 a = action_new(action_maximize_vert);
85 } else if (!g_ascii_strcasecmp(name, "unmaximizevert")) {
86 a = action_new(action_unmaximize_vert);
87 } else if (!g_ascii_strcasecmp(name, "togglemaximizevert")) {
88 a = action_new(action_toggle_maximize_vert);
89 } else if (!g_ascii_strcasecmp(name, "sendtonextdesktop")) {
90 a = action_new(action_send_to_next_desktop);
91 a->data.sendtonextprev.wrap = FALSE;
92 a->data.sendtonextprev.follow = TRUE;
93 } else if (!g_ascii_strcasecmp(name, "sendtonextdesktopwrap")) {
94 a = action_new(action_send_to_next_desktop);
95 a->data.sendtonextprev.wrap = TRUE;
96 a->data.sendtonextprev.follow = TRUE;
97 } else if (!g_ascii_strcasecmp(name, "sendtopreviousdesktop")) {
98 a = action_new(action_send_to_previous_desktop);
99 a->data.sendtonextprev.wrap = FALSE;
100 a->data.sendtonextprev.follow = TRUE;
101 } else if (!g_ascii_strcasecmp(name, "sendtopreviousdesktopwrap")) {
102 a = action_new(action_send_to_previous_desktop);
103 a->data.sendtonextprev.wrap = TRUE;
104 a->data.sendtonextprev.follow = TRUE;
105 } else if (!g_ascii_strcasecmp(name, "desktop")) {
106 a = action_new(action_desktop);
107 } else if (!g_ascii_strcasecmp(name, "nextdesktop")) {
108 a = action_new(action_next_desktop);
109 a->data.nextprevdesktop.wrap = FALSE;
110 } else if (!g_ascii_strcasecmp(name, "nextdesktopwrap")) {
111 a = action_new(action_next_desktop);
112 a->data.nextprevdesktop.wrap = TRUE;
113 } else if (!g_ascii_strcasecmp(name, "previousdesktop")) {
114 a = action_new(action_previous_desktop);
115 a->data.nextprevdesktop.wrap = FALSE;
116 } else if (!g_ascii_strcasecmp(name, "previousdesktopwrap")) {
117 a = action_new(action_previous_desktop);
118 a->data.nextprevdesktop.wrap = TRUE;
119 } else if (!g_ascii_strcasecmp(name, "nextdesktopcolumn")) {
120 a = action_new(action_next_desktop_column);
121 a->data.nextprevdesktop.wrap = FALSE;
122 } else if (!g_ascii_strcasecmp(name, "nextdesktopcolumnwrap")) {
123 a = action_new(action_next_desktop_column);
124 a->data.nextprevdesktop.wrap = TRUE;
125 } else if (!g_ascii_strcasecmp(name, "previousdesktopcolumn")) {
126 a = action_new(action_previous_desktop_column);
127 a->data.nextprevdesktop.wrap = FALSE;
128 } else if (!g_ascii_strcasecmp(name, "previousdesktopcolumnwrap")) {
129 a = action_new(action_previous_desktop_column);
130 a->data.nextprevdesktop.wrap = TRUE;
131 } else if (!g_ascii_strcasecmp(name, "nextdesktoprow")) {
132 a = action_new(action_next_desktop_row);
133 a->data.nextprevdesktop.wrap = FALSE;
134 } else if (!g_ascii_strcasecmp(name, "nextdesktoprowwrap")) {
135 a = action_new(action_next_desktop_row);
136 a->data.nextprevdesktop.wrap = TRUE;
137 } else if (!g_ascii_strcasecmp(name, "previousdesktoprow")) {
138 a = action_new(action_previous_desktop_row);
139 a->data.nextprevdesktop.wrap = FALSE;
140 } else if (!g_ascii_strcasecmp(name, "previousdesktoprowwrap")) {
141 a = action_new(action_previous_desktop_row);
142 a->data.nextprevdesktop.wrap = TRUE;
143 } else if (!g_ascii_strcasecmp(name, "toggledecorations")) {
144 a = action_new(action_toggle_decorations);
145 } else if (!g_ascii_strcasecmp(name, "move")) {
146 a = action_new(action_move);
147 } else if (!g_ascii_strcasecmp(name, "resize")) {
148 a = action_new(action_resize);
149 } else if (!g_ascii_strcasecmp(name, "restart")) {
150 a = action_new(action_restart);
151 } else if (!g_ascii_strcasecmp(name, "exit")) {
152 a = action_new(action_exit);
157 void action_execute(union ActionData *data)
160 if (data->execute.path)
161 if (!g_spawn_command_line_async(data->execute.path, &e)) {
162 g_warning("failed to execute '%s': %s",
163 data->execute.path, e->message);
167 void action_focus(union ActionData *data)
170 client_focus(data->client.c);
173 void action_unfocus (union ActionData *data)
176 client_unfocus(data->client.c);
179 void action_iconify(union ActionData *data)
182 client_iconify(data->client.c, TRUE, TRUE);
185 void action_focusraise(union ActionData *data)
187 if (data->client.c) {
188 client_focus(data->client.c);
189 stacking_raise(data->client.c);
193 void action_raise(union ActionData *data)
196 stacking_raise(data->client.c);
199 void action_lower(union ActionData *data)
202 stacking_lower(data->client.c);
205 void action_close(union ActionData *data)
208 client_close(data->client.c);
211 void action_kill(union ActionData *data)
214 client_kill(data->client.c);
217 void action_shade(union ActionData *data)
220 client_shade(data->client.c, TRUE);
223 void action_unshade(union ActionData *data)
226 client_shade(data->client.c, FALSE);
229 void action_toggle_shade(union ActionData *data)
232 client_shade(data->client.c, !data->client.c->shaded);
235 void action_toggle_omnipresent(union ActionData *data)
238 client_set_desktop(data->client.c,
239 data->client.c->desktop == DESKTOP_ALL ?
240 screen_desktop : DESKTOP_ALL, FALSE);
243 void action_move_relative_horz(union ActionData *data)
245 Client *c = data->relative.c;
247 client_configure(c, Corner_TopLeft,
248 c->area.x + data->relative.delta, c->area.y,
249 c->area.width, c->area.height, TRUE, TRUE);
252 void action_move_relative_vert(union ActionData *data)
254 Client *c = data->relative.c;
256 client_configure(c, Corner_TopLeft,
257 c->area.x, c->area.y + data->relative.delta,
258 c->area.width, c->area.height, TRUE, TRUE);
261 void action_resize_relative_horz(union ActionData *data)
263 Client *c = data->relative.c;
265 client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
266 c->area.width + data->relative.delta,
267 c->area.height, TRUE, TRUE);
270 void action_resize_relative_vert(union ActionData *data)
272 Client *c = data->relative.c;
274 client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
275 c->area.width, c->area.height + data->relative.delta,
279 void action_maximize_full(union ActionData *data)
282 client_maximize(data->client.c, TRUE, 0, TRUE);
285 void action_unmaximize_full(union ActionData *data)
288 client_maximize(data->client.c, FALSE, 0, TRUE);
291 void action_toggle_maximize_full(union ActionData *data)
294 client_maximize(data->client.c,
295 !(data->client.c->max_horz ||
296 data->client.c->max_vert),
300 void action_maximize_horz(union ActionData *data)
303 client_maximize(data->client.c, TRUE, 1, TRUE);
306 void action_unmaximize_horz(union ActionData *data)
309 client_maximize(data->client.c, FALSE, 1, TRUE);
312 void action_toggle_maximize_horz(union ActionData *data)
315 client_maximize(data->client.c, !data->client.c->max_horz, 1, TRUE);
318 void action_maximize_vert(union ActionData *data)
321 client_maximize(data->client.c, TRUE, 2, TRUE);
324 void action_unmaximize_vert(union ActionData *data)
327 client_maximize(data->client.c, FALSE, 2, TRUE);
330 void action_toggle_maximize_vert(union ActionData *data)
333 client_maximize(data->client.c, !data->client.c->max_vert, 2, TRUE);
336 void action_send_to_desktop(union ActionData *data)
339 if (data->sendto.desktop < screen_num_desktops ||
340 data->sendto.desktop == DESKTOP_ALL)
341 client_set_desktop(data->sendto.c, data->sendto.desktop, TRUE);
344 void action_send_to_next_desktop(union ActionData *data)
348 if (!data->sendto.c) return;
350 d = screen_desktop + 1;
351 if (d >= screen_num_desktops) {
352 if (!data->sendtonextprev.wrap) return;
355 client_set_desktop(data->sendtonextprev.c, d, data->sendtonextprev.follow);
356 if (data->sendtonextprev.follow) screen_set_desktop(d);
359 void action_send_to_previous_desktop(union ActionData *data)
363 if (!data->sendto.c) return;
365 d = screen_desktop - 1;
366 if (d >= screen_num_desktops) {
367 if (!data->sendtonextprev.wrap) return;
368 d = screen_num_desktops - 1;
370 client_set_desktop(data->sendtonextprev.c, d, data->sendtonextprev.follow);
371 if (data->sendtonextprev.follow) screen_set_desktop(d);
374 void action_desktop(union ActionData *data)
376 if (data->desktop.desk < screen_num_desktops ||
377 data->desktop.desk == DESKTOP_ALL)
378 screen_set_desktop(data->desktop.desk);
381 void action_next_desktop(union ActionData *data)
385 d = screen_desktop + 1;
386 if (d >= screen_num_desktops) {
387 if (!data->nextprevdesktop.wrap) return;
390 screen_set_desktop(d);
393 void action_previous_desktop(union ActionData *data)
397 d = screen_desktop - 1;
398 if (d >= screen_num_desktops) {
399 if (!data->nextprevdesktop.wrap) return;
400 d = screen_num_desktops - 1;
402 screen_set_desktop(d);
405 static void cur_row_col(guint *r, guint *c)
407 switch (screen_desktop_layout.orientation) {
408 case Orientation_Horz:
409 switch (screen_desktop_layout.start_corner) {
411 *r = screen_desktop / screen_desktop_layout.columns;
412 *c = screen_desktop % screen_desktop_layout.columns;
414 case Corner_BottomLeft:
415 *r = screen_desktop_layout.rows - 1 -
416 screen_desktop / screen_desktop_layout.columns;
417 *c = screen_desktop % screen_desktop_layout.columns;
420 case Corner_TopRight:
421 *r = screen_desktop / screen_desktop_layout.columns;
422 *c = screen_desktop_layout.columns - 1 -
423 screen_desktop % screen_desktop_layout.columns;
425 case Corner_BottomRight:
426 *r = screen_desktop_layout.rows - 1 -
427 screen_desktop / screen_desktop_layout.columns;
428 *c = screen_desktop_layout.columns - 1 -
429 screen_desktop % screen_desktop_layout.columns;
433 case Orientation_Vert:
434 switch (screen_desktop_layout.start_corner) {
436 *r = screen_desktop % screen_desktop_layout.rows;
437 *c = screen_desktop / screen_desktop_layout.rows;
439 case Corner_BottomLeft:
440 *r = screen_desktop_layout.rows - 1 -
441 screen_desktop % screen_desktop_layout.rows;
442 *c = screen_desktop / screen_desktop_layout.rows;
445 case Corner_TopRight:
446 *r = screen_desktop % screen_desktop_layout.rows;
447 *c = screen_desktop_layout.columns - 1 -
448 screen_desktop / screen_desktop_layout.rows;
450 case Corner_BottomRight:
451 *r = screen_desktop_layout.rows - 1 -
452 screen_desktop % screen_desktop_layout.rows;
453 *c = screen_desktop_layout.columns - 1 -
454 screen_desktop / screen_desktop_layout.rows;
462 static guint translate_row_col(guint r, guint c)
464 switch (screen_desktop_layout.orientation) {
465 case Orientation_Horz:
466 switch (screen_desktop_layout.start_corner) {
468 return r * screen_desktop_layout.columns + c;
469 case Corner_BottomLeft:
470 return (screen_desktop_layout.rows - 1 - r) *
471 screen_desktop_layout.columns + c;
472 case Corner_TopRight:
473 return r * screen_desktop_layout.columns +
474 (screen_desktop_layout.columns - 1 - c);
475 case Corner_BottomRight:
476 return (screen_desktop_layout.rows - 1 - r) *
477 screen_desktop_layout.columns +
478 (screen_desktop_layout.columns - 1 - c);
480 case Orientation_Vert:
481 switch (screen_desktop_layout.start_corner) {
483 return c * screen_desktop_layout.rows + r;
484 case Corner_BottomLeft:
485 return c * screen_desktop_layout.rows +
486 (screen_desktop_layout.rows - 1 - r);
487 case Corner_TopRight:
488 return (screen_desktop_layout.columns - 1 - c) *
489 screen_desktop_layout.rows + r;
490 case Corner_BottomRight:
491 return (screen_desktop_layout.columns - 1 - c) *
492 screen_desktop_layout.rows +
493 (screen_desktop_layout.rows - 1 - r);
496 g_assert_not_reached();
500 void action_next_desktop_column(union ActionData *data)
506 d = translate_row_col(r, c);
507 if (d >= screen_num_desktops) {
508 if (!data->nextprevdesktop.wrap) return;
511 if (d >= screen_num_desktops)
513 d = translate_row_col(r, c);
514 if (d < screen_num_desktops)
515 screen_set_desktop(d);
518 void action_previous_desktop_column(union ActionData *data)
524 d = translate_row_col(r, c);
525 if (d >= screen_num_desktops) {
526 if (!data->nextprevdesktop.wrap) return;
527 c = screen_desktop_layout.columns - 1;
529 if (d >= screen_num_desktops)
531 d = translate_row_col(r, c);
532 if (d < screen_num_desktops)
533 screen_set_desktop(d);
536 void action_next_desktop_row(union ActionData *data)
542 d = translate_row_col(r, c);
543 if (d >= screen_num_desktops) {
544 if (!data->nextprevdesktop.wrap) return;
547 if (d >= screen_num_desktops)
549 d = translate_row_col(r, c);
550 if (d < screen_num_desktops)
551 screen_set_desktop(d);
554 void action_previous_desktop_row(union ActionData *data)
560 d = translate_row_col(r, c);
561 if (d >= screen_num_desktops) {
562 if (!data->nextprevdesktop.wrap) return;
563 c = screen_desktop_layout.rows - 1;
565 if (d >= screen_num_desktops)
567 d = translate_row_col(r, c);
568 if (d < screen_num_desktops)
569 screen_set_desktop(d);
572 void action_toggle_decorations(union ActionData *data)
574 Client *c = data->client.c;
575 c->disabled_decorations = c->disabled_decorations ? 0 : ~0;
576 client_setup_decor_and_functions(c);
579 void action_move(union ActionData *data)
581 Client *c = data->move.c;
582 int x = data->move.x;
583 int y = data->move.y;
585 if (!c || !client_normal(c)) return;
587 dispatch_move(c, &x, &y);
589 frame_frame_gravity(c->frame, &x, &y); /* get where the client should be */
590 client_configure(c, Corner_TopLeft, x, y, c->area.width, c->area.height,
591 TRUE, data->move.final);
594 void action_resize(union ActionData *data)
596 Client *c = data->resize.c;
597 int w = data->resize.x;
598 int h = data->resize.y;
600 if (!c || !client_normal(c)) return;
602 dispatch_resize(c, &w, &h, data->resize.corner);
604 w -= c->frame->size.left + c->frame->size.right;
605 h -= c->frame->size.top + c->frame->size.bottom;
606 client_configure(c, data->resize.corner, c->area.x, c->area.y, w, h,
607 TRUE, data->resize.final);
610 void action_restart(union ActionData *data)
612 ob_restart_path = data->execute.path;
613 ob_shutdown = ob_restart = TRUE;
616 void action_exit(union ActionData *data)