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, "moverelative")) {
64 a = action_new(action_move_relative);
65 } else if (!g_ascii_strcasecmp(name, "resizerelative")) {
66 a = action_new(action_resize_relative);
67 } else if (!g_ascii_strcasecmp(name, "maximizefull")) {
68 a = action_new(action_maximize_full);
69 } else if (!g_ascii_strcasecmp(name, "unmaximizefull")) {
70 a = action_new(action_unmaximize_full);
71 } else if (!g_ascii_strcasecmp(name, "togglemaximizefull")) {
72 a = action_new(action_toggle_maximize_full);
73 } else if (!g_ascii_strcasecmp(name, "maximizehorz")) {
74 a = action_new(action_maximize_horz);
75 } else if (!g_ascii_strcasecmp(name, "unmaximizehorz")) {
76 a = action_new(action_unmaximize_horz);
77 } else if (!g_ascii_strcasecmp(name, "togglemaximizehorz")) {
78 a = action_new(action_toggle_maximize_horz);
79 } else if (!g_ascii_strcasecmp(name, "maximizevert")) {
80 a = action_new(action_maximize_vert);
81 } else if (!g_ascii_strcasecmp(name, "unmaximizevert")) {
82 a = action_new(action_unmaximize_vert);
83 } else if (!g_ascii_strcasecmp(name, "togglemaximizevert")) {
84 a = action_new(action_toggle_maximize_vert);
85 } else if (!g_ascii_strcasecmp(name, "sendtonextdesktop")) {
86 a = action_new(action_send_to_next_desktop);
87 a->data.sendtonextprev.wrap = FALSE;
88 a->data.sendtonextprev.follow = TRUE;
89 } else if (!g_ascii_strcasecmp(name, "sendtonextdesktopwrap")) {
90 a = action_new(action_send_to_next_desktop);
91 a->data.sendtonextprev.wrap = TRUE;
92 a->data.sendtonextprev.follow = TRUE;
93 } else if (!g_ascii_strcasecmp(name, "sendtopreviousdesktop")) {
94 a = action_new(action_send_to_previous_desktop);
95 a->data.sendtonextprev.wrap = FALSE;
96 a->data.sendtonextprev.follow = TRUE;
97 } else if (!g_ascii_strcasecmp(name, "sendtopreviousdesktopwrap")) {
98 a = action_new(action_send_to_previous_desktop);
99 a->data.sendtonextprev.wrap = TRUE;
100 a->data.sendtonextprev.follow = TRUE;
101 } else if (!g_ascii_strcasecmp(name, "desktop")) {
102 a = action_new(action_desktop);
103 } else if (!g_ascii_strcasecmp(name, "nextdesktop")) {
104 a = action_new(action_next_desktop);
105 a->data.nextprevdesktop.wrap = FALSE;
106 } else if (!g_ascii_strcasecmp(name, "nextdesktopwrap")) {
107 a = action_new(action_next_desktop);
108 a->data.nextprevdesktop.wrap = TRUE;
109 } else if (!g_ascii_strcasecmp(name, "previousdesktop")) {
110 a = action_new(action_previous_desktop);
111 a->data.nextprevdesktop.wrap = FALSE;
112 } else if (!g_ascii_strcasecmp(name, "previousdesktopwrap")) {
113 a = action_new(action_previous_desktop);
114 a->data.nextprevdesktop.wrap = TRUE;
115 } else if (!g_ascii_strcasecmp(name, "nextdesktopcolumn")) {
116 a = action_new(action_next_desktop_column);
117 a->data.nextprevdesktop.wrap = FALSE;
118 } else if (!g_ascii_strcasecmp(name, "nextdesktopcolumnwrap")) {
119 a = action_new(action_next_desktop_column);
120 a->data.nextprevdesktop.wrap = TRUE;
121 } else if (!g_ascii_strcasecmp(name, "previousdesktopcolumn")) {
122 a = action_new(action_previous_desktop_column);
123 a->data.nextprevdesktop.wrap = FALSE;
124 } else if (!g_ascii_strcasecmp(name, "previousdesktopcolumnwrap")) {
125 a = action_new(action_previous_desktop_column);
126 a->data.nextprevdesktop.wrap = TRUE;
127 } else if (!g_ascii_strcasecmp(name, "nextdesktoprow")) {
128 a = action_new(action_next_desktop_row);
129 a->data.nextprevdesktop.wrap = FALSE;
130 } else if (!g_ascii_strcasecmp(name, "nextdesktoprowwrap")) {
131 a = action_new(action_next_desktop_row);
132 a->data.nextprevdesktop.wrap = TRUE;
133 } else if (!g_ascii_strcasecmp(name, "previousdesktoprow")) {
134 a = action_new(action_previous_desktop_row);
135 a->data.nextprevdesktop.wrap = FALSE;
136 } else if (!g_ascii_strcasecmp(name, "previousdesktoprowwrap")) {
137 a = action_new(action_previous_desktop_row);
138 a->data.nextprevdesktop.wrap = TRUE;
139 } else if (!g_ascii_strcasecmp(name, "move")) {
140 a = action_new(action_move);
141 } else if (!g_ascii_strcasecmp(name, "resize")) {
142 a = action_new(action_resize);
143 } else if (!g_ascii_strcasecmp(name, "restart")) {
144 a = action_new(action_restart);
145 } else if (!g_ascii_strcasecmp(name, "exit")) {
146 a = action_new(action_exit);
151 void action_execute(union ActionData *data)
154 if (data->execute.path)
155 if (!g_spawn_command_line_async(data->execute.path, &e)) {
156 g_warning("failed to execute '%s': %s",
157 data->execute.path, e->message);
161 void action_focus(union ActionData *data)
164 client_focus(data->client.c);
167 void action_unfocus (union ActionData *data)
170 client_unfocus(data->client.c);
173 void action_iconify(union ActionData *data)
176 client_iconify(data->client.c, TRUE, TRUE);
179 void action_focusraise(union ActionData *data)
181 if (data->client.c) {
182 client_focus(data->client.c);
183 stacking_raise(data->client.c);
187 void action_raise(union ActionData *data)
190 stacking_raise(data->client.c);
193 void action_lower(union ActionData *data)
196 stacking_lower(data->client.c);
199 void action_close(union ActionData *data)
202 client_close(data->client.c);
205 void action_kill(union ActionData *data)
208 client_kill(data->client.c);
211 void action_shade(union ActionData *data)
214 client_shade(data->client.c, TRUE);
217 void action_unshade(union ActionData *data)
220 client_shade(data->client.c, FALSE);
223 void action_toggle_shade(union ActionData *data)
226 client_shade(data->client.c, !data->client.c->shaded);
229 void action_toggle_omnipresent(union ActionData *data)
232 client_set_desktop(data->client.c,
233 data->client.c->desktop == DESKTOP_ALL ?
234 screen_desktop : DESKTOP_ALL);
237 void action_move_relative(union ActionData *data)
239 Client *c = data->relative.c;
241 client_configure(c, Corner_TopLeft,
242 c->area.x + data->relative.dx,
243 c->area.y + data->relative.dy,
244 c->area.width, c->area.height, TRUE, TRUE);
247 void action_resize_relative(union ActionData *data)
249 Client *c = data->relative.c;
251 client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
252 c->area.width + data->relative.dx,
253 c->area.height + data->relative.dy, TRUE, TRUE);
256 void action_maximize_full(union ActionData *data)
259 client_maximize(data->client.c, TRUE, 0, TRUE);
262 void action_unmaximize_full(union ActionData *data)
265 client_maximize(data->client.c, FALSE, 0, TRUE);
268 void action_toggle_maximize_full(union ActionData *data)
271 client_maximize(data->client.c,
272 !(data->client.c->max_horz ||
273 data->client.c->max_vert),
277 void action_maximize_horz(union ActionData *data)
280 client_maximize(data->client.c, TRUE, 1, TRUE);
283 void action_unmaximize_horz(union ActionData *data)
286 client_maximize(data->client.c, FALSE, 1, TRUE);
289 void action_toggle_maximize_horz(union ActionData *data)
292 client_maximize(data->client.c, !data->client.c->max_horz, 1, TRUE);
295 void action_maximize_vert(union ActionData *data)
298 client_maximize(data->client.c, TRUE, 2, TRUE);
301 void action_unmaximize_vert(union ActionData *data)
304 client_maximize(data->client.c, FALSE, 2, TRUE);
307 void action_toggle_maximize_vert(union ActionData *data)
310 client_maximize(data->client.c, !data->client.c->max_vert, 2, TRUE);
313 void action_send_to_desktop(union ActionData *data)
316 if (data->sendto.desktop < screen_num_desktops ||
317 data->sendto.desktop == DESKTOP_ALL)
318 client_set_desktop(data->sendto.c, data->sendto.desktop);
321 void action_send_to_next_desktop(union ActionData *data)
325 if (!data->sendto.c) return;
327 d = screen_desktop + 1;
328 if (d >= screen_num_desktops) {
329 if (!data->sendtonextprev.wrap) return;
332 client_set_desktop(data->sendtonextprev.c, d);
333 if (data->sendtonextprev.follow) screen_set_desktop(d);
336 void action_send_to_previous_desktop(union ActionData *data)
340 if (!data->sendto.c) return;
342 d = screen_desktop - 1;
343 if (d >= screen_num_desktops) {
344 if (!data->sendtonextprev.wrap) return;
345 d = screen_num_desktops - 1;
347 client_set_desktop(data->sendtonextprev.c, d);
348 if (data->sendtonextprev.follow) screen_set_desktop(d);
351 void action_desktop(union ActionData *data)
353 if (data->desktop.desk < screen_num_desktops ||
354 data->desktop.desk == DESKTOP_ALL)
355 screen_set_desktop(data->desktop.desk);
358 void action_next_desktop(union ActionData *data)
362 d = screen_desktop + 1;
363 if (d >= screen_num_desktops) {
364 if (!data->nextprevdesktop.wrap) return;
367 screen_set_desktop(d);
370 void action_previous_desktop(union ActionData *data)
374 d = screen_desktop - 1;
375 if (d >= screen_num_desktops) {
376 if (!data->nextprevdesktop.wrap) return;
377 d = screen_num_desktops - 1;
379 screen_set_desktop(d);
382 static void cur_row_col(guint *r, guint *c)
384 switch (screen_desktop_layout.orientation) {
385 case Orientation_Horz:
386 switch (screen_desktop_layout.start_corner) {
388 *r = screen_desktop / screen_desktop_layout.columns;
389 *c = screen_desktop % screen_desktop_layout.columns;
391 case Corner_BottomLeft:
392 *r = screen_desktop_layout.rows - 1 -
393 screen_desktop / screen_desktop_layout.columns;
394 *c = screen_desktop % screen_desktop_layout.columns;
397 case Corner_TopRight:
398 *r = screen_desktop / screen_desktop_layout.columns;
399 *c = screen_desktop_layout.columns - 1 -
400 screen_desktop % screen_desktop_layout.columns;
402 case Corner_BottomRight:
403 *r = screen_desktop_layout.rows - 1 -
404 screen_desktop / screen_desktop_layout.columns;
405 *c = screen_desktop_layout.columns - 1 -
406 screen_desktop % screen_desktop_layout.columns;
410 case Orientation_Vert:
411 switch (screen_desktop_layout.start_corner) {
413 *r = screen_desktop % screen_desktop_layout.rows;
414 *c = screen_desktop / screen_desktop_layout.rows;
416 case Corner_BottomLeft:
417 *r = screen_desktop_layout.rows - 1 -
418 screen_desktop % screen_desktop_layout.rows;
419 *c = screen_desktop / screen_desktop_layout.rows;
422 case Corner_TopRight:
423 *r = screen_desktop % screen_desktop_layout.rows;
424 *c = screen_desktop_layout.columns - 1 -
425 screen_desktop / screen_desktop_layout.rows;
427 case Corner_BottomRight:
428 *r = screen_desktop_layout.rows - 1 -
429 screen_desktop % screen_desktop_layout.rows;
430 *c = screen_desktop_layout.columns - 1 -
431 screen_desktop / screen_desktop_layout.rows;
439 static guint translate_row_col(guint r, guint c)
441 switch (screen_desktop_layout.orientation) {
442 case Orientation_Horz:
443 switch (screen_desktop_layout.start_corner) {
445 return r * screen_desktop_layout.columns + c;
446 case Corner_BottomLeft:
447 return (screen_desktop_layout.rows - 1 - r) *
448 screen_desktop_layout.columns + c;
449 case Corner_TopRight:
450 return r * screen_desktop_layout.columns +
451 (screen_desktop_layout.columns - 1 - c);
452 case Corner_BottomRight:
453 return (screen_desktop_layout.rows - 1 - r) *
454 screen_desktop_layout.columns +
455 (screen_desktop_layout.columns - 1 - c);
457 case Orientation_Vert:
458 switch (screen_desktop_layout.start_corner) {
460 return c * screen_desktop_layout.rows + r;
461 case Corner_BottomLeft:
462 return c * screen_desktop_layout.rows +
463 (screen_desktop_layout.rows - 1 - r);
464 case Corner_TopRight:
465 return (screen_desktop_layout.columns - 1 - c) *
466 screen_desktop_layout.rows + r;
467 case Corner_BottomRight:
468 return (screen_desktop_layout.columns - 1 - c) *
469 screen_desktop_layout.rows +
470 (screen_desktop_layout.rows - 1 - r);
473 g_assert_not_reached();
477 void action_next_desktop_column(union ActionData *data)
483 d = translate_row_col(r, c);
484 if (d >= screen_num_desktops) {
485 if (!data->nextprevdesktop.wrap) return;
488 if (d >= screen_num_desktops)
490 d = translate_row_col(r, c);
491 if (d < screen_num_desktops)
492 screen_set_desktop(d);
495 void action_previous_desktop_column(union ActionData *data)
501 d = translate_row_col(r, c);
502 if (d >= screen_num_desktops) {
503 if (!data->nextprevdesktop.wrap) return;
504 c = screen_desktop_layout.columns - 1;
506 if (d >= screen_num_desktops)
508 d = translate_row_col(r, c);
509 if (d < screen_num_desktops)
510 screen_set_desktop(d);
513 void action_next_desktop_row(union ActionData *data)
519 d = translate_row_col(r, c);
520 if (d >= screen_num_desktops) {
521 if (!data->nextprevdesktop.wrap) return;
524 if (d >= screen_num_desktops)
526 d = translate_row_col(r, c);
527 if (d < screen_num_desktops)
528 screen_set_desktop(d);
531 void action_previous_desktop_row(union ActionData *data)
537 d = translate_row_col(r, c);
538 if (d >= screen_num_desktops) {
539 if (!data->nextprevdesktop.wrap) return;
540 c = screen_desktop_layout.rows - 1;
542 if (d >= screen_num_desktops)
544 d = translate_row_col(r, c);
545 if (d < screen_num_desktops)
546 screen_set_desktop(d);
549 void action_toggle_decorations(union ActionData *data)
551 Client *c = data->client.c;
552 c->disabled_decorations = c->disabled_decorations ? 0 : ~0;
553 client_setup_decor_and_functions(c);
556 void action_move(union ActionData *data)
558 Client *c = data->move.c;
559 int x = data->move.x;
560 int y = data->move.y;
562 if (!c || !client_normal(c)) return;
564 dispatch_move(c, &x, &y);
566 frame_frame_gravity(c->frame, &x, &y); /* get where the client should be */
567 client_configure(c, Corner_TopLeft, x, y, c->area.width, c->area.height,
568 TRUE, data->move.final);
571 void action_resize(union ActionData *data)
573 Client *c = data->resize.c;
574 int w = data->resize.x - c->frame->size.left - c->frame->size.right;
575 int h = data->resize.y - c->frame->size.top - c->frame->size.bottom;
577 if (!c || !client_normal(c)) return;
579 /* XXX window snapping/struts */
581 client_configure(c, data->resize.corner, c->area.x, c->area.y, w, h,
582 TRUE, data->resize.final);
585 void action_restart(union ActionData *data)
587 ob_restart_path = data->execute.path;
588 ob_shutdown = ob_restart = TRUE;
591 void action_exit(union ActionData *data)