]> Dogcows Code - chaz/openbox/blob - openbox/action.c
make SendToDesktop action work right, give the option of following
[chaz/openbox] / openbox / action.c
1 #include "client.h"
2 #include "stacking.h"
3 #include "frame.h"
4 #include "screen.h"
5 #include "action.h"
6 #include "dispatch.h"
7 #include "openbox.h"
8
9 #include <glib.h>
10
11 Action *action_new(void (*func)(union ActionData *data))
12 {
13 Action *a = g_new0(Action, 1);
14 a->func = func;
15
16 /* deal with pointers */
17 if (func == action_execute)
18 a->data.execute.path = NULL;
19
20 return a;
21 }
22
23 void action_free(Action *a)
24 {
25 if (a == NULL) return;
26
27 /* deal with pointers */
28 if (a->func == action_execute || a->func == action_restart)
29 g_free(a->data.execute.path);
30
31 g_free(a);
32 }
33
34 Action *action_from_string(char *name)
35 {
36 Action *a = NULL;
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, "shadelower")) {
56 a = action_new(action_shadelower);
57 } else if (!g_ascii_strcasecmp(name, "unshaderaise")) {
58 a = action_new(action_unshaderaise);
59 } else if (!g_ascii_strcasecmp(name, "shade")) {
60 a = action_new(action_shade);
61 } else if (!g_ascii_strcasecmp(name, "unshade")) {
62 a = action_new(action_unshade);
63 } else if (!g_ascii_strcasecmp(name, "toggleshade")) {
64 a = action_new(action_toggle_shade);
65 } else if (!g_ascii_strcasecmp(name, "toggleomnipresent")) {
66 a = action_new(action_toggle_omnipresent);
67 } else if (!g_ascii_strcasecmp(name, "moverelativehorz")) {
68 a = action_new(action_move_relative_horz);
69 } else if (!g_ascii_strcasecmp(name, "moverelativevert")) {
70 a = action_new(action_move_relative_vert);
71 } else if (!g_ascii_strcasecmp(name, "resizerelativehorz")) {
72 a = action_new(action_resize_relative_horz);
73 } else if (!g_ascii_strcasecmp(name, "resizerelativevert")) {
74 a = action_new(action_resize_relative_vert);
75 } else if (!g_ascii_strcasecmp(name, "maximizefull")) {
76 a = action_new(action_maximize_full);
77 } else if (!g_ascii_strcasecmp(name, "unmaximizefull")) {
78 a = action_new(action_unmaximize_full);
79 } else if (!g_ascii_strcasecmp(name, "togglemaximizefull")) {
80 a = action_new(action_toggle_maximize_full);
81 } else if (!g_ascii_strcasecmp(name, "maximizehorz")) {
82 a = action_new(action_maximize_horz);
83 } else if (!g_ascii_strcasecmp(name, "unmaximizehorz")) {
84 a = action_new(action_unmaximize_horz);
85 } else if (!g_ascii_strcasecmp(name, "togglemaximizehorz")) {
86 a = action_new(action_toggle_maximize_horz);
87 } else if (!g_ascii_strcasecmp(name, "maximizevert")) {
88 a = action_new(action_maximize_vert);
89 } else if (!g_ascii_strcasecmp(name, "unmaximizevert")) {
90 a = action_new(action_unmaximize_vert);
91 } else if (!g_ascii_strcasecmp(name, "togglemaximizevert")) {
92 a = action_new(action_toggle_maximize_vert);
93 } else if (!g_ascii_strcasecmp(name, "sendtodesktop")) {
94 a = action_new(action_send_to_desktop);
95 a->data.sendto.follow = TRUE;
96 } else if (!g_ascii_strcasecmp(name, "sendtonextdesktop")) {
97 a = action_new(action_send_to_next_desktop);
98 a->data.sendtonextprev.wrap = FALSE;
99 a->data.sendtonextprev.follow = TRUE;
100 } else if (!g_ascii_strcasecmp(name, "sendtonextdesktopwrap")) {
101 a = action_new(action_send_to_next_desktop);
102 a->data.sendtonextprev.wrap = TRUE;
103 a->data.sendtonextprev.follow = TRUE;
104 } else if (!g_ascii_strcasecmp(name, "sendtopreviousdesktop")) {
105 a = action_new(action_send_to_previous_desktop);
106 a->data.sendtonextprev.wrap = FALSE;
107 a->data.sendtonextprev.follow = TRUE;
108 } else if (!g_ascii_strcasecmp(name, "sendtopreviousdesktopwrap")) {
109 a = action_new(action_send_to_previous_desktop);
110 a->data.sendtonextprev.wrap = TRUE;
111 a->data.sendtonextprev.follow = TRUE;
112 } else if (!g_ascii_strcasecmp(name, "desktop")) {
113 a = action_new(action_desktop);
114 } else if (!g_ascii_strcasecmp(name, "nextdesktop")) {
115 a = action_new(action_next_desktop);
116 a->data.nextprevdesktop.wrap = FALSE;
117 } else if (!g_ascii_strcasecmp(name, "nextdesktopwrap")) {
118 a = action_new(action_next_desktop);
119 a->data.nextprevdesktop.wrap = TRUE;
120 } else if (!g_ascii_strcasecmp(name, "previousdesktop")) {
121 a = action_new(action_previous_desktop);
122 a->data.nextprevdesktop.wrap = FALSE;
123 } else if (!g_ascii_strcasecmp(name, "previousdesktopwrap")) {
124 a = action_new(action_previous_desktop);
125 a->data.nextprevdesktop.wrap = TRUE;
126 } else if (!g_ascii_strcasecmp(name, "nextdesktopcolumn")) {
127 a = action_new(action_next_desktop_column);
128 a->data.nextprevdesktop.wrap = FALSE;
129 } else if (!g_ascii_strcasecmp(name, "nextdesktopcolumnwrap")) {
130 a = action_new(action_next_desktop_column);
131 a->data.nextprevdesktop.wrap = TRUE;
132 } else if (!g_ascii_strcasecmp(name, "previousdesktopcolumn")) {
133 a = action_new(action_previous_desktop_column);
134 a->data.nextprevdesktop.wrap = FALSE;
135 } else if (!g_ascii_strcasecmp(name, "previousdesktopcolumnwrap")) {
136 a = action_new(action_previous_desktop_column);
137 a->data.nextprevdesktop.wrap = TRUE;
138 } else if (!g_ascii_strcasecmp(name, "nextdesktoprow")) {
139 a = action_new(action_next_desktop_row);
140 a->data.nextprevdesktop.wrap = FALSE;
141 } else if (!g_ascii_strcasecmp(name, "nextdesktoprowwrap")) {
142 a = action_new(action_next_desktop_row);
143 a->data.nextprevdesktop.wrap = TRUE;
144 } else if (!g_ascii_strcasecmp(name, "previousdesktoprow")) {
145 a = action_new(action_previous_desktop_row);
146 a->data.nextprevdesktop.wrap = FALSE;
147 } else if (!g_ascii_strcasecmp(name, "previousdesktoprowwrap")) {
148 a = action_new(action_previous_desktop_row);
149 a->data.nextprevdesktop.wrap = TRUE;
150 } else if (!g_ascii_strcasecmp(name, "toggledecorations")) {
151 a = action_new(action_toggle_decorations);
152 } else if (!g_ascii_strcasecmp(name, "move")) {
153 a = action_new(action_move);
154 } else if (!g_ascii_strcasecmp(name, "resize")) {
155 a = action_new(action_resize);
156 } else if (!g_ascii_strcasecmp(name, "restart")) {
157 a = action_new(action_restart);
158 } else if (!g_ascii_strcasecmp(name, "exit")) {
159 a = action_new(action_exit);
160 }
161 else if (!g_ascii_strcasecmp(name, "showmenu")) {
162 a = action_new(action_showmenu);
163 }
164
165 return a;
166 }
167
168 void action_execute(union ActionData *data)
169 {
170 GError *e = NULL;
171 if (data->execute.path)
172 if (!g_spawn_command_line_async(data->execute.path, &e)) {
173 g_warning("failed to execute '%s': %s",
174 data->execute.path, e->message);
175 }
176 }
177
178 void action_focus(union ActionData *data)
179 {
180 if (data->client.c)
181 client_focus(data->client.c);
182 }
183
184 void action_unfocus (union ActionData *data)
185 {
186 if (data->client.c)
187 client_unfocus(data->client.c);
188 }
189
190 void action_iconify(union ActionData *data)
191 {
192 if (data->client.c)
193 client_iconify(data->client.c, TRUE, TRUE);
194 }
195
196 void action_focusraise(union ActionData *data)
197 {
198 if (data->client.c) {
199 client_focus(data->client.c);
200 stacking_raise(data->client.c);
201 }
202 }
203
204 void action_raise(union ActionData *data)
205 {
206 if (data->client.c)
207 stacking_raise(data->client.c);
208 }
209
210 void action_unshaderaise(union ActionData *data)
211 {
212 if (data->client.c) {
213 if (data->client.c->shaded)
214 client_shade(data->client.c, FALSE);
215 else
216 stacking_raise(data->client.c);
217 }
218 }
219
220 void action_shadelower(union ActionData *data)
221 {
222 if (data->client.c) {
223 if (data->client.c->shaded)
224 stacking_lower(data->client.c);
225 else
226 client_shade(data->client.c, TRUE);
227 }
228 }
229
230 void action_lower(union ActionData *data)
231 {
232 if (data->client.c)
233 stacking_lower(data->client.c);
234 }
235
236 void action_close(union ActionData *data)
237 {
238 if (data->client.c)
239 client_close(data->client.c);
240 }
241
242 void action_kill(union ActionData *data)
243 {
244 if (data->client.c)
245 client_kill(data->client.c);
246 }
247
248 void action_shade(union ActionData *data)
249 {
250 if (data->client.c)
251 client_shade(data->client.c, TRUE);
252 }
253
254 void action_unshade(union ActionData *data)
255 {
256 if (data->client.c)
257 client_shade(data->client.c, FALSE);
258 }
259
260 void action_toggle_shade(union ActionData *data)
261 {
262 if (data->client.c)
263 client_shade(data->client.c, !data->client.c->shaded);
264 }
265
266 void action_toggle_omnipresent(union ActionData *data)
267 {
268 if (data->client.c)
269 client_set_desktop(data->client.c,
270 data->client.c->desktop == DESKTOP_ALL ?
271 screen_desktop : DESKTOP_ALL, FALSE);
272 }
273
274 void action_move_relative_horz(union ActionData *data)
275 {
276 Client *c = data->relative.c;
277 if (c)
278 client_configure(c, Corner_TopLeft,
279 c->area.x + data->relative.delta, c->area.y,
280 c->area.width, c->area.height, TRUE, TRUE);
281 }
282
283 void action_move_relative_vert(union ActionData *data)
284 {
285 Client *c = data->relative.c;
286 if (c)
287 client_configure(c, Corner_TopLeft,
288 c->area.x, c->area.y + data->relative.delta,
289 c->area.width, c->area.height, TRUE, TRUE);
290 }
291
292 void action_resize_relative_horz(union ActionData *data)
293 {
294 Client *c = data->relative.c;
295 if (c)
296 client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
297 c->area.width + data->relative.delta,
298 c->area.height, TRUE, TRUE);
299 }
300
301 void action_resize_relative_vert(union ActionData *data)
302 {
303 Client *c = data->relative.c;
304 if (c)
305 client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
306 c->area.width, c->area.height + data->relative.delta,
307 TRUE, TRUE);
308 }
309
310 void action_maximize_full(union ActionData *data)
311 {
312 if (data->client.c)
313 client_maximize(data->client.c, TRUE, 0, TRUE);
314 }
315
316 void action_unmaximize_full(union ActionData *data)
317 {
318 if (data->client.c)
319 client_maximize(data->client.c, FALSE, 0, TRUE);
320 }
321
322 void action_toggle_maximize_full(union ActionData *data)
323 {
324 if (data->client.c)
325 client_maximize(data->client.c,
326 !(data->client.c->max_horz ||
327 data->client.c->max_vert),
328 0, TRUE);
329 }
330
331 void action_maximize_horz(union ActionData *data)
332 {
333 if (data->client.c)
334 client_maximize(data->client.c, TRUE, 1, TRUE);
335 }
336
337 void action_unmaximize_horz(union ActionData *data)
338 {
339 if (data->client.c)
340 client_maximize(data->client.c, FALSE, 1, TRUE);
341 }
342
343 void action_toggle_maximize_horz(union ActionData *data)
344 {
345 if (data->client.c)
346 client_maximize(data->client.c, !data->client.c->max_horz, 1, TRUE);
347 }
348
349 void action_maximize_vert(union ActionData *data)
350 {
351 if (data->client.c)
352 client_maximize(data->client.c, TRUE, 2, TRUE);
353 }
354
355 void action_unmaximize_vert(union ActionData *data)
356 {
357 if (data->client.c)
358 client_maximize(data->client.c, FALSE, 2, TRUE);
359 }
360
361 void action_toggle_maximize_vert(union ActionData *data)
362 {
363 if (data->client.c)
364 client_maximize(data->client.c, !data->client.c->max_vert, 2, TRUE);
365 }
366
367 void action_send_to_desktop(union ActionData *data)
368 {
369 if (data->sendto.c) {
370 if (data->sendto.desk < screen_num_desktops ||
371 data->sendto.desk == DESKTOP_ALL) {
372 client_set_desktop(data->desktop.c,
373 data->sendto.desk, data->sendto.follow);
374 if (data->sendto.follow) screen_set_desktop(data->sendto.desk);
375 }
376 }
377 }
378
379 void action_send_to_next_desktop(union ActionData *data)
380 {
381 guint d;
382
383 if (!data->sendtonextprev.c) return;
384
385 d = screen_desktop + 1;
386 if (d >= screen_num_desktops) {
387 if (!data->sendtonextprev.wrap) return;
388 d = 0;
389 }
390 client_set_desktop(data->sendtonextprev.c, d, data->sendtonextprev.follow);
391 if (data->sendtonextprev.follow) screen_set_desktop(d);
392 }
393
394 void action_send_to_previous_desktop(union ActionData *data)
395 {
396 guint d;
397
398 if (!data->sendtonextprev.c) return;
399
400 d = screen_desktop - 1;
401 if (d >= screen_num_desktops) {
402 if (!data->sendtonextprev.wrap) return;
403 d = screen_num_desktops - 1;
404 }
405 client_set_desktop(data->sendtonextprev.c, d, data->sendtonextprev.follow);
406 if (data->sendtonextprev.follow) screen_set_desktop(d);
407 }
408
409 void action_desktop(union ActionData *data)
410 {
411 if (data->desktop.desk < screen_num_desktops ||
412 data->desktop.desk == DESKTOP_ALL)
413 screen_set_desktop(data->desktop.desk);
414 }
415
416 void action_next_desktop(union ActionData *data)
417 {
418 guint d;
419
420 d = screen_desktop + 1;
421 if (d >= screen_num_desktops) {
422 if (!data->nextprevdesktop.wrap) return;
423 d = 0;
424 }
425 screen_set_desktop(d);
426 }
427
428 void action_previous_desktop(union ActionData *data)
429 {
430 guint d;
431
432 d = screen_desktop - 1;
433 if (d >= screen_num_desktops) {
434 if (!data->nextprevdesktop.wrap) return;
435 d = screen_num_desktops - 1;
436 }
437 screen_set_desktop(d);
438 }
439
440 static void cur_row_col(guint *r, guint *c)
441 {
442 switch (screen_desktop_layout.orientation) {
443 case Orientation_Horz:
444 switch (screen_desktop_layout.start_corner) {
445 case Corner_TopLeft:
446 *r = screen_desktop / screen_desktop_layout.columns;
447 *c = screen_desktop % screen_desktop_layout.columns;
448 break;
449 case Corner_BottomLeft:
450 *r = screen_desktop_layout.rows - 1 -
451 screen_desktop / screen_desktop_layout.columns;
452 *c = screen_desktop % screen_desktop_layout.columns;
453 break;
454 break;
455 case Corner_TopRight:
456 *r = screen_desktop / screen_desktop_layout.columns;
457 *c = screen_desktop_layout.columns - 1 -
458 screen_desktop % screen_desktop_layout.columns;
459 break;
460 case Corner_BottomRight:
461 *r = screen_desktop_layout.rows - 1 -
462 screen_desktop / screen_desktop_layout.columns;
463 *c = screen_desktop_layout.columns - 1 -
464 screen_desktop % screen_desktop_layout.columns;
465 break;
466 break;
467 }
468 case Orientation_Vert:
469 switch (screen_desktop_layout.start_corner) {
470 case Corner_TopLeft:
471 *r = screen_desktop % screen_desktop_layout.rows;
472 *c = screen_desktop / screen_desktop_layout.rows;
473 break;
474 case Corner_BottomLeft:
475 *r = screen_desktop_layout.rows - 1 -
476 screen_desktop % screen_desktop_layout.rows;
477 *c = screen_desktop / screen_desktop_layout.rows;
478 break;
479 break;
480 case Corner_TopRight:
481 *r = screen_desktop % screen_desktop_layout.rows;
482 *c = screen_desktop_layout.columns - 1 -
483 screen_desktop / screen_desktop_layout.rows;
484 break;
485 case Corner_BottomRight:
486 *r = screen_desktop_layout.rows - 1 -
487 screen_desktop % screen_desktop_layout.rows;
488 *c = screen_desktop_layout.columns - 1 -
489 screen_desktop / screen_desktop_layout.rows;
490 break;
491 break;
492 }
493 break;
494 }
495 }
496
497 static guint translate_row_col(guint r, guint c)
498 {
499 switch (screen_desktop_layout.orientation) {
500 case Orientation_Horz:
501 switch (screen_desktop_layout.start_corner) {
502 case Corner_TopLeft:
503 return r * screen_desktop_layout.columns + c;
504 case Corner_BottomLeft:
505 return (screen_desktop_layout.rows - 1 - r) *
506 screen_desktop_layout.columns + c;
507 case Corner_TopRight:
508 return r * screen_desktop_layout.columns +
509 (screen_desktop_layout.columns - 1 - c);
510 case Corner_BottomRight:
511 return (screen_desktop_layout.rows - 1 - r) *
512 screen_desktop_layout.columns +
513 (screen_desktop_layout.columns - 1 - c);
514 }
515 case Orientation_Vert:
516 switch (screen_desktop_layout.start_corner) {
517 case Corner_TopLeft:
518 return c * screen_desktop_layout.rows + r;
519 case Corner_BottomLeft:
520 return c * screen_desktop_layout.rows +
521 (screen_desktop_layout.rows - 1 - r);
522 case Corner_TopRight:
523 return (screen_desktop_layout.columns - 1 - c) *
524 screen_desktop_layout.rows + r;
525 case Corner_BottomRight:
526 return (screen_desktop_layout.columns - 1 - c) *
527 screen_desktop_layout.rows +
528 (screen_desktop_layout.rows - 1 - r);
529 }
530 }
531 g_assert_not_reached();
532 return 0;
533 }
534
535 void action_next_desktop_column(union ActionData *data)
536 {
537 guint r, c, d;
538
539 cur_row_col(&r, &c);
540 ++c;
541 d = translate_row_col(r, c);
542 if (d >= screen_num_desktops) {
543 if (!data->nextprevdesktop.wrap) return;
544 c = 0;
545 }
546 if (d >= screen_num_desktops)
547 ++c;
548 d = translate_row_col(r, c);
549 if (d < screen_num_desktops)
550 screen_set_desktop(d);
551 }
552
553 void action_previous_desktop_column(union ActionData *data)
554 {
555 guint r, c, d;
556
557 cur_row_col(&r, &c);
558 --c;
559 d = translate_row_col(r, c);
560 if (d >= screen_num_desktops) {
561 if (!data->nextprevdesktop.wrap) return;
562 c = screen_desktop_layout.columns - 1;
563 }
564 if (d >= screen_num_desktops)
565 --c;
566 d = translate_row_col(r, c);
567 if (d < screen_num_desktops)
568 screen_set_desktop(d);
569 }
570
571 void action_next_desktop_row(union ActionData *data)
572 {
573 guint r, c, d;
574
575 cur_row_col(&r, &c);
576 ++r;
577 d = translate_row_col(r, c);
578 if (d >= screen_num_desktops) {
579 if (!data->nextprevdesktop.wrap) return;
580 r = 0;
581 }
582 if (d >= screen_num_desktops)
583 ++r;
584 d = translate_row_col(r, c);
585 if (d < screen_num_desktops)
586 screen_set_desktop(d);
587 }
588
589 void action_previous_desktop_row(union ActionData *data)
590 {
591 guint r, c, d;
592
593 cur_row_col(&r, &c);
594 --r;
595 d = translate_row_col(r, c);
596 if (d >= screen_num_desktops) {
597 if (!data->nextprevdesktop.wrap) return;
598 c = screen_desktop_layout.rows - 1;
599 }
600 if (d >= screen_num_desktops)
601 --r;
602 d = translate_row_col(r, c);
603 if (d < screen_num_desktops)
604 screen_set_desktop(d);
605 }
606
607 void action_toggle_decorations(union ActionData *data)
608 {
609 Client *c = data->client.c;
610 c->disabled_decorations = c->disabled_decorations ? 0 : ~0;
611 client_setup_decor_and_functions(c);
612 }
613
614 void action_move(union ActionData *data)
615 {
616 Client *c = data->move.c;
617 int x = data->move.x;
618 int y = data->move.y;
619
620 if (!c || !client_normal(c)) return;
621
622 dispatch_move(c, &x, &y);
623
624 frame_frame_gravity(c->frame, &x, &y); /* get where the client should be */
625 client_configure(c, Corner_TopLeft, x, y, c->area.width, c->area.height,
626 TRUE, data->move.final);
627 }
628
629 void action_resize(union ActionData *data)
630 {
631 Client *c = data->resize.c;
632 int w = data->resize.x;
633 int h = data->resize.y;
634
635 if (!c || !client_normal(c)) return;
636
637 /* XXX window snapping/struts */
638
639 dispatch_resize(c, &w, &h, data->resize.corner);
640
641 w -= c->frame->size.left + c->frame->size.right;
642 h -= c->frame->size.top + c->frame->size.bottom;
643
644 client_configure(c, data->resize.corner, c->area.x, c->area.y, w, h,
645 TRUE, data->resize.final);
646 }
647
648 void action_restart(union ActionData *data)
649 {
650 ob_restart_path = data->execute.path;
651 ob_shutdown = ob_restart = TRUE;
652 }
653
654 void action_exit(union ActionData *data)
655 {
656 ob_shutdown = TRUE;
657 }
658
659 void action_showmenu(union ActionData *data)
660 {
661 g_message(__FUNCTION__);
662 }
This page took 0.075134 seconds and 5 git commands to generate.