12 Action
*action_new(void (*func
)(union ActionData
*data
))
14 Action
*a
= g_new0(Action
, 1);
17 /* deal with pointers */
18 if (func
== action_execute
)
19 a
->data
.execute
.path
= NULL
;
24 void action_free(Action
*a
)
26 if (a
== NULL
) return;
28 /* deal with pointers */
29 if (a
->func
== action_execute
|| a
->func
== action_restart
)
30 g_free(a
->data
.execute
.path
);
35 Action
*action_from_string(char *name
)
38 if (!g_ascii_strcasecmp(name
, "execute")) {
39 a
= action_new(action_execute
);
40 } else if (!g_ascii_strcasecmp(name
, "focus")) {
41 a
= action_new(action_focus
);
42 } else if (!g_ascii_strcasecmp(name
, "unfocus")) {
43 a
= action_new(action_unfocus
);
44 } else if (!g_ascii_strcasecmp(name
, "iconify")) {
45 a
= action_new(action_iconify
);
46 } else if (!g_ascii_strcasecmp(name
, "raise")) {
47 a
= action_new(action_raise
);
48 } else if (!g_ascii_strcasecmp(name
, "lower")) {
49 a
= action_new(action_lower
);
50 } else if (!g_ascii_strcasecmp(name
, "focusraise")) {
51 a
= action_new(action_focusraise
);
52 } else if (!g_ascii_strcasecmp(name
, "close")) {
53 a
= action_new(action_close
);
54 } else if (!g_ascii_strcasecmp(name
, "kill")) {
55 a
= action_new(action_kill
);
56 } else if (!g_ascii_strcasecmp(name
, "shadelower")) {
57 a
= action_new(action_shadelower
);
58 } else if (!g_ascii_strcasecmp(name
, "unshaderaise")) {
59 a
= action_new(action_unshaderaise
);
60 } else if (!g_ascii_strcasecmp(name
, "shade")) {
61 a
= action_new(action_shade
);
62 } else if (!g_ascii_strcasecmp(name
, "unshade")) {
63 a
= action_new(action_unshade
);
64 } else if (!g_ascii_strcasecmp(name
, "toggleshade")) {
65 a
= action_new(action_toggle_shade
);
66 } else if (!g_ascii_strcasecmp(name
, "toggleomnipresent")) {
67 a
= action_new(action_toggle_omnipresent
);
68 } else if (!g_ascii_strcasecmp(name
, "moverelativehorz")) {
69 a
= action_new(action_move_relative_horz
);
70 } else if (!g_ascii_strcasecmp(name
, "moverelativevert")) {
71 a
= action_new(action_move_relative_vert
);
72 } else if (!g_ascii_strcasecmp(name
, "resizerelativehorz")) {
73 a
= action_new(action_resize_relative_horz
);
74 } else if (!g_ascii_strcasecmp(name
, "resizerelativevert")) {
75 a
= action_new(action_resize_relative_vert
);
76 } else if (!g_ascii_strcasecmp(name
, "maximizefull")) {
77 a
= action_new(action_maximize_full
);
78 } else if (!g_ascii_strcasecmp(name
, "unmaximizefull")) {
79 a
= action_new(action_unmaximize_full
);
80 } else if (!g_ascii_strcasecmp(name
, "togglemaximizefull")) {
81 a
= action_new(action_toggle_maximize_full
);
82 } else if (!g_ascii_strcasecmp(name
, "maximizehorz")) {
83 a
= action_new(action_maximize_horz
);
84 } else if (!g_ascii_strcasecmp(name
, "unmaximizehorz")) {
85 a
= action_new(action_unmaximize_horz
);
86 } else if (!g_ascii_strcasecmp(name
, "togglemaximizehorz")) {
87 a
= action_new(action_toggle_maximize_horz
);
88 } else if (!g_ascii_strcasecmp(name
, "maximizevert")) {
89 a
= action_new(action_maximize_vert
);
90 } else if (!g_ascii_strcasecmp(name
, "unmaximizevert")) {
91 a
= action_new(action_unmaximize_vert
);
92 } else if (!g_ascii_strcasecmp(name
, "togglemaximizevert")) {
93 a
= action_new(action_toggle_maximize_vert
);
94 } else if (!g_ascii_strcasecmp(name
, "sendtodesktop")) {
95 a
= action_new(action_send_to_desktop
);
96 a
->data
.sendto
.follow
= TRUE
;
97 } else if (!g_ascii_strcasecmp(name
, "sendtonextdesktop")) {
98 a
= action_new(action_send_to_next_desktop
);
99 a
->data
.sendtonextprev
.wrap
= FALSE
;
100 a
->data
.sendtonextprev
.follow
= TRUE
;
101 } else if (!g_ascii_strcasecmp(name
, "sendtonextdesktopwrap")) {
102 a
= action_new(action_send_to_next_desktop
);
103 a
->data
.sendtonextprev
.wrap
= TRUE
;
104 a
->data
.sendtonextprev
.follow
= TRUE
;
105 } else if (!g_ascii_strcasecmp(name
, "sendtopreviousdesktop")) {
106 a
= action_new(action_send_to_previous_desktop
);
107 a
->data
.sendtonextprev
.wrap
= FALSE
;
108 a
->data
.sendtonextprev
.follow
= TRUE
;
109 } else if (!g_ascii_strcasecmp(name
, "sendtopreviousdesktopwrap")) {
110 a
= action_new(action_send_to_previous_desktop
);
111 a
->data
.sendtonextprev
.wrap
= TRUE
;
112 a
->data
.sendtonextprev
.follow
= TRUE
;
113 } else if (!g_ascii_strcasecmp(name
, "desktop")) {
114 a
= action_new(action_desktop
);
115 } else if (!g_ascii_strcasecmp(name
, "nextdesktop")) {
116 a
= action_new(action_next_desktop
);
117 a
->data
.nextprevdesktop
.wrap
= FALSE
;
118 } else if (!g_ascii_strcasecmp(name
, "nextdesktopwrap")) {
119 a
= action_new(action_next_desktop
);
120 a
->data
.nextprevdesktop
.wrap
= TRUE
;
121 } else if (!g_ascii_strcasecmp(name
, "previousdesktop")) {
122 a
= action_new(action_previous_desktop
);
123 a
->data
.nextprevdesktop
.wrap
= FALSE
;
124 } else if (!g_ascii_strcasecmp(name
, "previousdesktopwrap")) {
125 a
= action_new(action_previous_desktop
);
126 a
->data
.nextprevdesktop
.wrap
= TRUE
;
127 } else if (!g_ascii_strcasecmp(name
, "nextdesktopcolumn")) {
128 a
= action_new(action_next_desktop_column
);
129 a
->data
.nextprevdesktop
.wrap
= FALSE
;
130 } else if (!g_ascii_strcasecmp(name
, "nextdesktopcolumnwrap")) {
131 a
= action_new(action_next_desktop_column
);
132 a
->data
.nextprevdesktop
.wrap
= TRUE
;
133 } else if (!g_ascii_strcasecmp(name
, "previousdesktopcolumn")) {
134 a
= action_new(action_previous_desktop_column
);
135 a
->data
.nextprevdesktop
.wrap
= FALSE
;
136 } else if (!g_ascii_strcasecmp(name
, "previousdesktopcolumnwrap")) {
137 a
= action_new(action_previous_desktop_column
);
138 a
->data
.nextprevdesktop
.wrap
= TRUE
;
139 } else if (!g_ascii_strcasecmp(name
, "nextdesktoprow")) {
140 a
= action_new(action_next_desktop_row
);
141 a
->data
.nextprevdesktop
.wrap
= FALSE
;
142 } else if (!g_ascii_strcasecmp(name
, "nextdesktoprowwrap")) {
143 a
= action_new(action_next_desktop_row
);
144 a
->data
.nextprevdesktop
.wrap
= TRUE
;
145 } else if (!g_ascii_strcasecmp(name
, "previousdesktoprow")) {
146 a
= action_new(action_previous_desktop_row
);
147 a
->data
.nextprevdesktop
.wrap
= FALSE
;
148 } else if (!g_ascii_strcasecmp(name
, "previousdesktoprowwrap")) {
149 a
= action_new(action_previous_desktop_row
);
150 a
->data
.nextprevdesktop
.wrap
= TRUE
;
151 } else if (!g_ascii_strcasecmp(name
, "toggledecorations")) {
152 a
= action_new(action_toggle_decorations
);
153 } else if (!g_ascii_strcasecmp(name
, "move")) {
154 a
= action_new(action_move
);
155 } else if (!g_ascii_strcasecmp(name
, "resize")) {
156 a
= action_new(action_resize
);
157 } else if (!g_ascii_strcasecmp(name
, "restart")) {
158 a
= action_new(action_restart
);
159 } else if (!g_ascii_strcasecmp(name
, "exit")) {
160 a
= action_new(action_exit
);
161 } else if (!g_ascii_strcasecmp(name
, "showmenu")) {
162 a
= action_new(action_showmenu
);
163 } else if (!g_ascii_strcasecmp(name
, "nextwindowlinear")) {
164 a
= action_new(action_cycle_windows
);
165 a
->data
.cycle
.linear
= TRUE
;
166 a
->data
.cycle
.forward
= TRUE
;
167 } else if (!g_ascii_strcasecmp(name
, "previouswindowlinear")) {
168 a
= action_new(action_cycle_windows
);
169 a
->data
.cycle
.linear
= TRUE
;
170 a
->data
.cycle
.forward
= FALSE
;
176 void action_execute(union ActionData
*data
)
179 if (data
->execute
.path
)
180 if (!g_spawn_command_line_async(data
->execute
.path
, &e
)) {
181 g_warning("failed to execute '%s': %s",
182 data
->execute
.path
, e
->message
);
186 void action_focus(union ActionData
*data
)
189 client_focus(data
->client
.c
);
192 void action_unfocus (union ActionData
*data
)
195 client_unfocus(data
->client
.c
);
198 void action_iconify(union ActionData
*data
)
201 client_iconify(data
->client
.c
, TRUE
, TRUE
);
204 void action_focusraise(union ActionData
*data
)
206 if (data
->client
.c
) {
207 client_focus(data
->client
.c
);
208 stacking_raise(data
->client
.c
);
212 void action_raise(union ActionData
*data
)
215 stacking_raise(data
->client
.c
);
218 void action_unshaderaise(union ActionData
*data
)
220 if (data
->client
.c
) {
221 if (data
->client
.c
->shaded
)
222 client_shade(data
->client
.c
, FALSE
);
224 stacking_raise(data
->client
.c
);
228 void action_shadelower(union ActionData
*data
)
230 if (data
->client
.c
) {
231 if (data
->client
.c
->shaded
)
232 stacking_lower(data
->client
.c
);
234 client_shade(data
->client
.c
, TRUE
);
238 void action_lower(union ActionData
*data
)
241 stacking_lower(data
->client
.c
);
244 void action_close(union ActionData
*data
)
247 client_close(data
->client
.c
);
250 void action_kill(union ActionData
*data
)
253 client_kill(data
->client
.c
);
256 void action_shade(union ActionData
*data
)
259 client_shade(data
->client
.c
, TRUE
);
262 void action_unshade(union ActionData
*data
)
265 client_shade(data
->client
.c
, FALSE
);
268 void action_toggle_shade(union ActionData
*data
)
271 client_shade(data
->client
.c
, !data
->client
.c
->shaded
);
274 void action_toggle_omnipresent(union ActionData
*data
)
277 client_set_desktop(data
->client
.c
,
278 data
->client
.c
->desktop
== DESKTOP_ALL
?
279 screen_desktop
: DESKTOP_ALL
, FALSE
);
282 void action_move_relative_horz(union ActionData
*data
)
284 Client
*c
= data
->relative
.c
;
286 client_configure(c
, Corner_TopLeft
,
287 c
->area
.x
+ data
->relative
.delta
, c
->area
.y
,
288 c
->area
.width
, c
->area
.height
, TRUE
, TRUE
);
291 void action_move_relative_vert(union ActionData
*data
)
293 Client
*c
= data
->relative
.c
;
295 client_configure(c
, Corner_TopLeft
,
296 c
->area
.x
, c
->area
.y
+ data
->relative
.delta
,
297 c
->area
.width
, c
->area
.height
, TRUE
, TRUE
);
300 void action_resize_relative_horz(union ActionData
*data
)
302 Client
*c
= data
->relative
.c
;
304 client_configure(c
, Corner_TopLeft
, c
->area
.x
, c
->area
.y
,
305 c
->area
.width
+ data
->relative
.delta
,
306 c
->area
.height
, TRUE
, TRUE
);
309 void action_resize_relative_vert(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
, c
->area
.height
+ data
->relative
.delta
,
318 void action_maximize_full(union ActionData
*data
)
321 client_maximize(data
->client
.c
, TRUE
, 0, TRUE
);
324 void action_unmaximize_full(union ActionData
*data
)
327 client_maximize(data
->client
.c
, FALSE
, 0, TRUE
);
330 void action_toggle_maximize_full(union ActionData
*data
)
333 client_maximize(data
->client
.c
,
334 !(data
->client
.c
->max_horz
||
335 data
->client
.c
->max_vert
),
339 void action_maximize_horz(union ActionData
*data
)
342 client_maximize(data
->client
.c
, TRUE
, 1, TRUE
);
345 void action_unmaximize_horz(union ActionData
*data
)
348 client_maximize(data
->client
.c
, FALSE
, 1, TRUE
);
351 void action_toggle_maximize_horz(union ActionData
*data
)
354 client_maximize(data
->client
.c
, !data
->client
.c
->max_horz
, 1, TRUE
);
357 void action_maximize_vert(union ActionData
*data
)
360 client_maximize(data
->client
.c
, TRUE
, 2, TRUE
);
363 void action_unmaximize_vert(union ActionData
*data
)
366 client_maximize(data
->client
.c
, FALSE
, 2, TRUE
);
369 void action_toggle_maximize_vert(union ActionData
*data
)
372 client_maximize(data
->client
.c
, !data
->client
.c
->max_vert
, 2, TRUE
);
375 void action_send_to_desktop(union ActionData
*data
)
377 if (data
->sendto
.c
) {
378 if (data
->sendto
.desk
< screen_num_desktops
||
379 data
->sendto
.desk
== DESKTOP_ALL
) {
380 client_set_desktop(data
->desktop
.c
,
381 data
->sendto
.desk
, data
->sendto
.follow
);
382 if (data
->sendto
.follow
) screen_set_desktop(data
->sendto
.desk
);
387 void action_send_to_next_desktop(union ActionData
*data
)
391 if (!data
->sendtonextprev
.c
) return;
393 d
= screen_desktop
+ 1;
394 if (d
>= screen_num_desktops
) {
395 if (!data
->sendtonextprev
.wrap
) return;
398 client_set_desktop(data
->sendtonextprev
.c
, d
, data
->sendtonextprev
.follow
);
399 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
402 void action_send_to_previous_desktop(union ActionData
*data
)
406 if (!data
->sendtonextprev
.c
) return;
408 d
= screen_desktop
- 1;
409 if (d
>= screen_num_desktops
) {
410 if (!data
->sendtonextprev
.wrap
) return;
411 d
= screen_num_desktops
- 1;
413 client_set_desktop(data
->sendtonextprev
.c
, d
, data
->sendtonextprev
.follow
);
414 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
417 void action_desktop(union ActionData
*data
)
419 if (data
->desktop
.desk
< screen_num_desktops
||
420 data
->desktop
.desk
== DESKTOP_ALL
)
421 screen_set_desktop(data
->desktop
.desk
);
424 void action_next_desktop(union ActionData
*data
)
428 d
= screen_desktop
+ 1;
429 if (d
>= screen_num_desktops
) {
430 if (!data
->nextprevdesktop
.wrap
) return;
433 screen_set_desktop(d
);
436 void action_previous_desktop(union ActionData
*data
)
440 d
= screen_desktop
- 1;
441 if (d
>= screen_num_desktops
) {
442 if (!data
->nextprevdesktop
.wrap
) return;
443 d
= screen_num_desktops
- 1;
445 screen_set_desktop(d
);
448 static void cur_row_col(guint
*r
, guint
*c
)
450 switch (screen_desktop_layout
.orientation
) {
451 case Orientation_Horz
:
452 switch (screen_desktop_layout
.start_corner
) {
454 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
455 *c
= screen_desktop
% screen_desktop_layout
.columns
;
457 case Corner_BottomLeft
:
458 *r
= screen_desktop_layout
.rows
- 1 -
459 screen_desktop
/ screen_desktop_layout
.columns
;
460 *c
= screen_desktop
% screen_desktop_layout
.columns
;
462 case Corner_TopRight
:
463 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
464 *c
= screen_desktop_layout
.columns
- 1 -
465 screen_desktop
% screen_desktop_layout
.columns
;
467 case Corner_BottomRight
:
468 *r
= screen_desktop_layout
.rows
- 1 -
469 screen_desktop
/ screen_desktop_layout
.columns
;
470 *c
= screen_desktop_layout
.columns
- 1 -
471 screen_desktop
% screen_desktop_layout
.columns
;
475 case Orientation_Vert
:
476 switch (screen_desktop_layout
.start_corner
) {
478 *r
= screen_desktop
% screen_desktop_layout
.rows
;
479 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
481 case Corner_BottomLeft
:
482 *r
= screen_desktop_layout
.rows
- 1 -
483 screen_desktop
% screen_desktop_layout
.rows
;
484 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
486 case Corner_TopRight
:
487 *r
= screen_desktop
% screen_desktop_layout
.rows
;
488 *c
= screen_desktop_layout
.columns
- 1 -
489 screen_desktop
/ screen_desktop_layout
.rows
;
491 case Corner_BottomRight
:
492 *r
= screen_desktop_layout
.rows
- 1 -
493 screen_desktop
% screen_desktop_layout
.rows
;
494 *c
= screen_desktop_layout
.columns
- 1 -
495 screen_desktop
/ screen_desktop_layout
.rows
;
502 static guint
translate_row_col(guint r
, guint c
)
504 switch (screen_desktop_layout
.orientation
) {
505 case Orientation_Horz
:
506 switch (screen_desktop_layout
.start_corner
) {
508 return r
* screen_desktop_layout
.columns
+ c
;
509 case Corner_BottomLeft
:
510 return (screen_desktop_layout
.rows
- 1 - r
) *
511 screen_desktop_layout
.columns
+ c
;
512 case Corner_TopRight
:
513 return r
* screen_desktop_layout
.columns
+
514 (screen_desktop_layout
.columns
- 1 - c
);
515 case Corner_BottomRight
:
516 return (screen_desktop_layout
.rows
- 1 - r
) *
517 screen_desktop_layout
.columns
+
518 (screen_desktop_layout
.columns
- 1 - c
);
520 case Orientation_Vert
:
521 switch (screen_desktop_layout
.start_corner
) {
523 return c
* screen_desktop_layout
.rows
+ r
;
524 case Corner_BottomLeft
:
525 return c
* screen_desktop_layout
.rows
+
526 (screen_desktop_layout
.rows
- 1 - r
);
527 case Corner_TopRight
:
528 return (screen_desktop_layout
.columns
- 1 - c
) *
529 screen_desktop_layout
.rows
+ r
;
530 case Corner_BottomRight
:
531 return (screen_desktop_layout
.columns
- 1 - c
) *
532 screen_desktop_layout
.rows
+
533 (screen_desktop_layout
.rows
- 1 - r
);
536 g_assert_not_reached();
540 void action_next_desktop_column(union ActionData
*data
)
546 d
= translate_row_col(r
, c
);
547 if (d
>= screen_num_desktops
) {
548 if (!data
->nextprevdesktop
.wrap
) return;
551 if (d
>= screen_num_desktops
)
553 d
= translate_row_col(r
, c
);
554 if (d
< screen_num_desktops
)
555 screen_set_desktop(d
);
558 void action_previous_desktop_column(union ActionData
*data
)
564 d
= translate_row_col(r
, c
);
565 if (d
>= screen_num_desktops
) {
566 if (!data
->nextprevdesktop
.wrap
) return;
567 c
= screen_desktop_layout
.columns
- 1;
569 if (d
>= screen_num_desktops
)
571 d
= translate_row_col(r
, c
);
572 if (d
< screen_num_desktops
)
573 screen_set_desktop(d
);
576 void action_next_desktop_row(union ActionData
*data
)
582 d
= translate_row_col(r
, c
);
583 if (d
>= screen_num_desktops
) {
584 if (!data
->nextprevdesktop
.wrap
) return;
587 if (d
>= screen_num_desktops
)
589 d
= translate_row_col(r
, c
);
590 if (d
< screen_num_desktops
)
591 screen_set_desktop(d
);
594 void action_previous_desktop_row(union ActionData
*data
)
600 d
= translate_row_col(r
, c
);
601 if (d
>= screen_num_desktops
) {
602 if (!data
->nextprevdesktop
.wrap
) return;
603 c
= screen_desktop_layout
.rows
- 1;
605 if (d
>= screen_num_desktops
)
607 d
= translate_row_col(r
, c
);
608 if (d
< screen_num_desktops
)
609 screen_set_desktop(d
);
612 void action_toggle_decorations(union ActionData
*data
)
614 Client
*c
= data
->client
.c
;
615 c
->disabled_decorations
= c
->disabled_decorations
? 0 : ~0;
616 client_setup_decor_and_functions(c
);
619 void action_move(union ActionData
*data
)
621 Client
*c
= data
->move
.c
;
622 int x
= data
->move
.x
;
623 int y
= data
->move
.y
;
625 if (!c
|| !client_normal(c
)) return;
627 dispatch_move(c
, &x
, &y
);
629 frame_frame_gravity(c
->frame
, &x
, &y
); /* get where the client should be */
630 client_configure(c
, Corner_TopLeft
, x
, y
, c
->area
.width
, c
->area
.height
,
631 TRUE
, data
->move
.final
);
634 void action_resize(union ActionData
*data
)
636 Client
*c
= data
->resize
.c
;
637 int w
= data
->resize
.x
;
638 int h
= data
->resize
.y
;
640 if (!c
|| c
->shaded
|| !client_normal(c
)) return;
642 dispatch_resize(c
, &w
, &h
, data
->resize
.corner
);
644 w
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
645 h
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
647 client_configure(c
, data
->resize
.corner
, c
->area
.x
, c
->area
.y
, w
, h
,
648 TRUE
, data
->resize
.final
);
651 void action_restart(union ActionData
*data
)
653 ob_restart_path
= data
->execute
.path
;
654 ob_shutdown
= ob_restart
= TRUE
;
657 void action_exit(union ActionData
*data
)
662 void action_showmenu(union ActionData
*data
)
664 g_message(__FUNCTION__
);
667 void action_cycle_windows(union ActionData
*data
)
669 if (data
->cycle
.linear
) {
670 static Client
*first
= NULL
;
671 static Client
*t
= NULL
;
673 if (data
->cycle
.cancel
) {
674 if (first
) client_focus(first
);
675 } else if (!data
->cycle
.final
) {
679 first
= focus_client
;
680 start
= it
= g_list_find(client_list
, data
->cycle
.c
);
682 if (data
->cycle
.forward
) {
684 if (it
== NULL
) it
= client_list
;
687 if (it
== NULL
) it
= g_list_last(client_list
);
689 if (client_focus(it
->data
)) {
693 } while (it
!= start
);
695 if (t
) stacking_raise(t
);