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
, "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 } else if (!g_ascii_strcasecmp(name
, "showmenu")) {
161 a
= action_new(action_showmenu
);
162 } else if (!g_ascii_strcasecmp(name
, "nextwindowlinear")) {
163 a
= action_new(action_cycle_windows
);
164 a
->data
.cycle
.linear
= TRUE
;
165 a
->data
.cycle
.forward
= TRUE
;
166 } else if (!g_ascii_strcasecmp(name
, "previouswindowlinear")) {
167 a
= action_new(action_cycle_windows
);
168 a
->data
.cycle
.linear
= TRUE
;
169 a
->data
.cycle
.forward
= FALSE
;
175 void action_execute(union ActionData
*data
)
178 if (data
->execute
.path
)
179 if (!g_spawn_command_line_async(data
->execute
.path
, &e
)) {
180 g_warning("failed to execute '%s': %s",
181 data
->execute
.path
, e
->message
);
185 void action_focus(union ActionData
*data
)
188 client_focus(data
->client
.c
);
191 void action_unfocus (union ActionData
*data
)
194 client_unfocus(data
->client
.c
);
197 void action_iconify(union ActionData
*data
)
200 client_iconify(data
->client
.c
, TRUE
, TRUE
);
203 void action_focusraise(union ActionData
*data
)
205 if (data
->client
.c
) {
206 client_focus(data
->client
.c
);
207 stacking_raise(data
->client
.c
);
211 void action_raise(union ActionData
*data
)
214 stacking_raise(data
->client
.c
);
217 void action_unshaderaise(union ActionData
*data
)
219 if (data
->client
.c
) {
220 if (data
->client
.c
->shaded
)
221 client_shade(data
->client
.c
, FALSE
);
223 stacking_raise(data
->client
.c
);
227 void action_shadelower(union ActionData
*data
)
229 if (data
->client
.c
) {
230 if (data
->client
.c
->shaded
)
231 stacking_lower(data
->client
.c
);
233 client_shade(data
->client
.c
, TRUE
);
237 void action_lower(union ActionData
*data
)
240 stacking_lower(data
->client
.c
);
243 void action_close(union ActionData
*data
)
246 client_close(data
->client
.c
);
249 void action_kill(union ActionData
*data
)
252 client_kill(data
->client
.c
);
255 void action_shade(union ActionData
*data
)
258 client_shade(data
->client
.c
, TRUE
);
261 void action_unshade(union ActionData
*data
)
264 client_shade(data
->client
.c
, FALSE
);
267 void action_toggle_shade(union ActionData
*data
)
270 client_shade(data
->client
.c
, !data
->client
.c
->shaded
);
273 void action_toggle_omnipresent(union ActionData
*data
)
276 client_set_desktop(data
->client
.c
,
277 data
->client
.c
->desktop
== DESKTOP_ALL
?
278 screen_desktop
: DESKTOP_ALL
, FALSE
);
281 void action_move_relative_horz(union ActionData
*data
)
283 Client
*c
= data
->relative
.c
;
285 client_configure(c
, Corner_TopLeft
,
286 c
->area
.x
+ data
->relative
.delta
, c
->area
.y
,
287 c
->area
.width
, c
->area
.height
, TRUE
, TRUE
);
290 void action_move_relative_vert(union ActionData
*data
)
292 Client
*c
= data
->relative
.c
;
294 client_configure(c
, Corner_TopLeft
,
295 c
->area
.x
, c
->area
.y
+ data
->relative
.delta
,
296 c
->area
.width
, c
->area
.height
, TRUE
, TRUE
);
299 void action_resize_relative_horz(union ActionData
*data
)
301 Client
*c
= data
->relative
.c
;
303 client_configure(c
, Corner_TopLeft
, c
->area
.x
, c
->area
.y
,
304 c
->area
.width
+ data
->relative
.delta
,
305 c
->area
.height
, TRUE
, TRUE
);
308 void action_resize_relative_vert(union ActionData
*data
)
310 Client
*c
= data
->relative
.c
;
312 client_configure(c
, Corner_TopLeft
, c
->area
.x
, c
->area
.y
,
313 c
->area
.width
, c
->area
.height
+ data
->relative
.delta
,
317 void action_maximize_full(union ActionData
*data
)
320 client_maximize(data
->client
.c
, TRUE
, 0, TRUE
);
323 void action_unmaximize_full(union ActionData
*data
)
326 client_maximize(data
->client
.c
, FALSE
, 0, TRUE
);
329 void action_toggle_maximize_full(union ActionData
*data
)
332 client_maximize(data
->client
.c
,
333 !(data
->client
.c
->max_horz
||
334 data
->client
.c
->max_vert
),
338 void action_maximize_horz(union ActionData
*data
)
341 client_maximize(data
->client
.c
, TRUE
, 1, TRUE
);
344 void action_unmaximize_horz(union ActionData
*data
)
347 client_maximize(data
->client
.c
, FALSE
, 1, TRUE
);
350 void action_toggle_maximize_horz(union ActionData
*data
)
353 client_maximize(data
->client
.c
, !data
->client
.c
->max_horz
, 1, TRUE
);
356 void action_maximize_vert(union ActionData
*data
)
359 client_maximize(data
->client
.c
, TRUE
, 2, TRUE
);
362 void action_unmaximize_vert(union ActionData
*data
)
365 client_maximize(data
->client
.c
, FALSE
, 2, TRUE
);
368 void action_toggle_maximize_vert(union ActionData
*data
)
371 client_maximize(data
->client
.c
, !data
->client
.c
->max_vert
, 2, TRUE
);
374 void action_send_to_desktop(union ActionData
*data
)
376 if (data
->sendto
.c
) {
377 if (data
->sendto
.desk
< screen_num_desktops
||
378 data
->sendto
.desk
== DESKTOP_ALL
) {
379 client_set_desktop(data
->desktop
.c
,
380 data
->sendto
.desk
, data
->sendto
.follow
);
381 if (data
->sendto
.follow
) screen_set_desktop(data
->sendto
.desk
);
386 void action_send_to_next_desktop(union ActionData
*data
)
390 if (!data
->sendtonextprev
.c
) return;
392 d
= screen_desktop
+ 1;
393 if (d
>= screen_num_desktops
) {
394 if (!data
->sendtonextprev
.wrap
) return;
397 client_set_desktop(data
->sendtonextprev
.c
, d
, data
->sendtonextprev
.follow
);
398 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
401 void action_send_to_previous_desktop(union ActionData
*data
)
405 if (!data
->sendtonextprev
.c
) return;
407 d
= screen_desktop
- 1;
408 if (d
>= screen_num_desktops
) {
409 if (!data
->sendtonextprev
.wrap
) return;
410 d
= screen_num_desktops
- 1;
412 client_set_desktop(data
->sendtonextprev
.c
, d
, data
->sendtonextprev
.follow
);
413 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
416 void action_desktop(union ActionData
*data
)
418 if (data
->desktop
.desk
< screen_num_desktops
||
419 data
->desktop
.desk
== DESKTOP_ALL
)
420 screen_set_desktop(data
->desktop
.desk
);
423 void action_next_desktop(union ActionData
*data
)
427 d
= screen_desktop
+ 1;
428 if (d
>= screen_num_desktops
) {
429 if (!data
->nextprevdesktop
.wrap
) return;
432 screen_set_desktop(d
);
435 void action_previous_desktop(union ActionData
*data
)
439 d
= screen_desktop
- 1;
440 if (d
>= screen_num_desktops
) {
441 if (!data
->nextprevdesktop
.wrap
) return;
442 d
= screen_num_desktops
- 1;
444 screen_set_desktop(d
);
447 static void cur_row_col(guint
*r
, guint
*c
)
449 switch (screen_desktop_layout
.orientation
) {
450 case Orientation_Horz
:
451 switch (screen_desktop_layout
.start_corner
) {
453 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
454 *c
= screen_desktop
% screen_desktop_layout
.columns
;
456 case Corner_BottomLeft
:
457 *r
= screen_desktop_layout
.rows
- 1 -
458 screen_desktop
/ screen_desktop_layout
.columns
;
459 *c
= screen_desktop
% screen_desktop_layout
.columns
;
461 case Corner_TopRight
:
462 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
463 *c
= screen_desktop_layout
.columns
- 1 -
464 screen_desktop
% screen_desktop_layout
.columns
;
466 case Corner_BottomRight
:
467 *r
= screen_desktop_layout
.rows
- 1 -
468 screen_desktop
/ screen_desktop_layout
.columns
;
469 *c
= screen_desktop_layout
.columns
- 1 -
470 screen_desktop
% screen_desktop_layout
.columns
;
474 case Orientation_Vert
:
475 switch (screen_desktop_layout
.start_corner
) {
477 *r
= screen_desktop
% screen_desktop_layout
.rows
;
478 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
480 case Corner_BottomLeft
:
481 *r
= screen_desktop_layout
.rows
- 1 -
482 screen_desktop
% screen_desktop_layout
.rows
;
483 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
485 case Corner_TopRight
:
486 *r
= screen_desktop
% screen_desktop_layout
.rows
;
487 *c
= screen_desktop_layout
.columns
- 1 -
488 screen_desktop
/ screen_desktop_layout
.rows
;
490 case Corner_BottomRight
:
491 *r
= screen_desktop_layout
.rows
- 1 -
492 screen_desktop
% screen_desktop_layout
.rows
;
493 *c
= screen_desktop_layout
.columns
- 1 -
494 screen_desktop
/ screen_desktop_layout
.rows
;
501 static guint
translate_row_col(guint r
, guint c
)
503 switch (screen_desktop_layout
.orientation
) {
504 case Orientation_Horz
:
505 switch (screen_desktop_layout
.start_corner
) {
507 return r
* screen_desktop_layout
.columns
+ c
;
508 case Corner_BottomLeft
:
509 return (screen_desktop_layout
.rows
- 1 - r
) *
510 screen_desktop_layout
.columns
+ c
;
511 case Corner_TopRight
:
512 return r
* screen_desktop_layout
.columns
+
513 (screen_desktop_layout
.columns
- 1 - c
);
514 case Corner_BottomRight
:
515 return (screen_desktop_layout
.rows
- 1 - r
) *
516 screen_desktop_layout
.columns
+
517 (screen_desktop_layout
.columns
- 1 - c
);
519 case Orientation_Vert
:
520 switch (screen_desktop_layout
.start_corner
) {
522 return c
* screen_desktop_layout
.rows
+ r
;
523 case Corner_BottomLeft
:
524 return c
* screen_desktop_layout
.rows
+
525 (screen_desktop_layout
.rows
- 1 - r
);
526 case Corner_TopRight
:
527 return (screen_desktop_layout
.columns
- 1 - c
) *
528 screen_desktop_layout
.rows
+ r
;
529 case Corner_BottomRight
:
530 return (screen_desktop_layout
.columns
- 1 - c
) *
531 screen_desktop_layout
.rows
+
532 (screen_desktop_layout
.rows
- 1 - r
);
535 g_assert_not_reached();
539 void action_next_desktop_column(union ActionData
*data
)
545 d
= translate_row_col(r
, c
);
546 if (d
>= screen_num_desktops
) {
547 if (!data
->nextprevdesktop
.wrap
) return;
550 if (d
>= screen_num_desktops
)
552 d
= translate_row_col(r
, c
);
553 if (d
< screen_num_desktops
)
554 screen_set_desktop(d
);
557 void action_previous_desktop_column(union ActionData
*data
)
563 d
= translate_row_col(r
, c
);
564 if (d
>= screen_num_desktops
) {
565 if (!data
->nextprevdesktop
.wrap
) return;
566 c
= screen_desktop_layout
.columns
- 1;
568 if (d
>= screen_num_desktops
)
570 d
= translate_row_col(r
, c
);
571 if (d
< screen_num_desktops
)
572 screen_set_desktop(d
);
575 void action_next_desktop_row(union ActionData
*data
)
581 d
= translate_row_col(r
, c
);
582 if (d
>= screen_num_desktops
) {
583 if (!data
->nextprevdesktop
.wrap
) return;
586 if (d
>= screen_num_desktops
)
588 d
= translate_row_col(r
, c
);
589 if (d
< screen_num_desktops
)
590 screen_set_desktop(d
);
593 void action_previous_desktop_row(union ActionData
*data
)
599 d
= translate_row_col(r
, c
);
600 if (d
>= screen_num_desktops
) {
601 if (!data
->nextprevdesktop
.wrap
) return;
602 c
= screen_desktop_layout
.rows
- 1;
604 if (d
>= screen_num_desktops
)
606 d
= translate_row_col(r
, c
);
607 if (d
< screen_num_desktops
)
608 screen_set_desktop(d
);
611 void action_toggle_decorations(union ActionData
*data
)
613 Client
*c
= data
->client
.c
;
614 c
->disabled_decorations
= c
->disabled_decorations
? 0 : ~0;
615 client_setup_decor_and_functions(c
);
618 void action_move(union ActionData
*data
)
620 Client
*c
= data
->move
.c
;
621 int x
= data
->move
.x
;
622 int y
= data
->move
.y
;
624 if (!c
|| !client_normal(c
)) return;
626 dispatch_move(c
, &x
, &y
);
628 frame_frame_gravity(c
->frame
, &x
, &y
); /* get where the client should be */
629 client_configure(c
, Corner_TopLeft
, x
, y
, c
->area
.width
, c
->area
.height
,
630 TRUE
, data
->move
.final
);
633 void action_resize(union ActionData
*data
)
635 Client
*c
= data
->resize
.c
;
636 int w
= data
->resize
.x
;
637 int h
= data
->resize
.y
;
639 if (!c
|| c
->shaded
|| !client_normal(c
)) return;
641 dispatch_resize(c
, &w
, &h
, data
->resize
.corner
);
643 w
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
644 h
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
646 client_configure(c
, data
->resize
.corner
, c
->area
.x
, c
->area
.y
, w
, h
,
647 TRUE
, data
->resize
.final
);
650 void action_restart(union ActionData
*data
)
652 ob_restart_path
= data
->execute
.path
;
653 ob_shutdown
= ob_restart
= TRUE
;
656 void action_exit(union ActionData
*data
)
661 void action_showmenu(union ActionData
*data
)
663 g_message(__FUNCTION__
);
666 void action_cycle_windows(union ActionData
*data
)
668 if (data
->cycle
.linear
) {
669 if (!data
->cycle
.final
) {
672 start
= it
= g_list_find(client_list
, data
->cycle
.c
);
674 if (data
->cycle
.forward
) {
676 if (it
== NULL
) it
= client_list
;
679 if (it
== NULL
) it
= g_list_last(client_list
);
681 if (client_focus(it
->data
))
683 } while (it
!= start
);