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
;
171 } else if (!g_ascii_strcasecmp(name
, "nextwindow")) {
172 a
= action_new(action_cycle_windows
);
173 a
->data
.cycle
.linear
= FALSE
;
174 a
->data
.cycle
.forward
= TRUE
;
175 } else if (!g_ascii_strcasecmp(name
, "previouswindow")) {
176 a
= action_new(action_cycle_windows
);
177 a
->data
.cycle
.linear
= FALSE
;
178 a
->data
.cycle
.forward
= FALSE
;
184 void action_execute(union ActionData
*data
)
187 if (data
->execute
.path
)
188 if (!g_spawn_command_line_async(data
->execute
.path
, &e
)) {
189 g_warning("failed to execute '%s': %s",
190 data
->execute
.path
, e
->message
);
194 void action_focus(union ActionData
*data
)
197 client_focus(data
->client
.c
);
200 void action_unfocus (union ActionData
*data
)
203 client_unfocus(data
->client
.c
);
206 void action_iconify(union ActionData
*data
)
209 client_iconify(data
->client
.c
, TRUE
, TRUE
);
212 void action_focusraise(union ActionData
*data
)
214 if (data
->client
.c
) {
215 client_focus(data
->client
.c
);
216 stacking_raise(data
->client
.c
);
220 void action_raise(union ActionData
*data
)
223 stacking_raise(data
->client
.c
);
226 void action_unshaderaise(union ActionData
*data
)
228 if (data
->client
.c
) {
229 if (data
->client
.c
->shaded
)
230 client_shade(data
->client
.c
, FALSE
);
232 stacking_raise(data
->client
.c
);
236 void action_shadelower(union ActionData
*data
)
238 if (data
->client
.c
) {
239 if (data
->client
.c
->shaded
)
240 stacking_lower(data
->client
.c
);
242 client_shade(data
->client
.c
, TRUE
);
246 void action_lower(union ActionData
*data
)
249 stacking_lower(data
->client
.c
);
252 void action_close(union ActionData
*data
)
255 client_close(data
->client
.c
);
258 void action_kill(union ActionData
*data
)
261 client_kill(data
->client
.c
);
264 void action_shade(union ActionData
*data
)
267 client_shade(data
->client
.c
, TRUE
);
270 void action_unshade(union ActionData
*data
)
273 client_shade(data
->client
.c
, FALSE
);
276 void action_toggle_shade(union ActionData
*data
)
279 client_shade(data
->client
.c
, !data
->client
.c
->shaded
);
282 void action_toggle_omnipresent(union ActionData
*data
)
285 client_set_desktop(data
->client
.c
,
286 data
->client
.c
->desktop
== DESKTOP_ALL
?
287 screen_desktop
: DESKTOP_ALL
, FALSE
);
290 void action_move_relative_horz(union ActionData
*data
)
292 Client
*c
= data
->relative
.c
;
294 client_configure(c
, Corner_TopLeft
,
295 c
->area
.x
+ data
->relative
.delta
, c
->area
.y
,
296 c
->area
.width
, c
->area
.height
, TRUE
, TRUE
);
299 void action_move_relative_vert(union ActionData
*data
)
301 Client
*c
= data
->relative
.c
;
303 client_configure(c
, Corner_TopLeft
,
304 c
->area
.x
, c
->area
.y
+ data
->relative
.delta
,
305 c
->area
.width
, c
->area
.height
, TRUE
, TRUE
);
308 void action_resize_relative_horz(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
+ data
->relative
.delta
,
314 c
->area
.height
, TRUE
, TRUE
);
317 void action_resize_relative_vert(union ActionData
*data
)
319 Client
*c
= data
->relative
.c
;
321 client_configure(c
, Corner_TopLeft
, c
->area
.x
, c
->area
.y
,
322 c
->area
.width
, c
->area
.height
+ data
->relative
.delta
,
326 void action_maximize_full(union ActionData
*data
)
329 client_maximize(data
->client
.c
, TRUE
, 0, TRUE
);
332 void action_unmaximize_full(union ActionData
*data
)
335 client_maximize(data
->client
.c
, FALSE
, 0, TRUE
);
338 void action_toggle_maximize_full(union ActionData
*data
)
341 client_maximize(data
->client
.c
,
342 !(data
->client
.c
->max_horz
||
343 data
->client
.c
->max_vert
),
347 void action_maximize_horz(union ActionData
*data
)
350 client_maximize(data
->client
.c
, TRUE
, 1, TRUE
);
353 void action_unmaximize_horz(union ActionData
*data
)
356 client_maximize(data
->client
.c
, FALSE
, 1, TRUE
);
359 void action_toggle_maximize_horz(union ActionData
*data
)
362 client_maximize(data
->client
.c
, !data
->client
.c
->max_horz
, 1, TRUE
);
365 void action_maximize_vert(union ActionData
*data
)
368 client_maximize(data
->client
.c
, TRUE
, 2, TRUE
);
371 void action_unmaximize_vert(union ActionData
*data
)
374 client_maximize(data
->client
.c
, FALSE
, 2, TRUE
);
377 void action_toggle_maximize_vert(union ActionData
*data
)
380 client_maximize(data
->client
.c
, !data
->client
.c
->max_vert
, 2, TRUE
);
383 void action_send_to_desktop(union ActionData
*data
)
385 if (data
->sendto
.c
) {
386 if (data
->sendto
.desk
< screen_num_desktops
||
387 data
->sendto
.desk
== DESKTOP_ALL
) {
388 client_set_desktop(data
->desktop
.c
,
389 data
->sendto
.desk
, data
->sendto
.follow
);
390 if (data
->sendto
.follow
) screen_set_desktop(data
->sendto
.desk
);
395 void action_send_to_next_desktop(union ActionData
*data
)
399 if (!data
->sendtonextprev
.c
) return;
401 d
= screen_desktop
+ 1;
402 if (d
>= screen_num_desktops
) {
403 if (!data
->sendtonextprev
.wrap
) return;
406 client_set_desktop(data
->sendtonextprev
.c
, d
, data
->sendtonextprev
.follow
);
407 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
410 void action_send_to_previous_desktop(union ActionData
*data
)
414 if (!data
->sendtonextprev
.c
) return;
416 d
= screen_desktop
- 1;
417 if (d
>= screen_num_desktops
) {
418 if (!data
->sendtonextprev
.wrap
) return;
419 d
= screen_num_desktops
- 1;
421 client_set_desktop(data
->sendtonextprev
.c
, d
, data
->sendtonextprev
.follow
);
422 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
425 void action_desktop(union ActionData
*data
)
427 if (data
->desktop
.desk
< screen_num_desktops
||
428 data
->desktop
.desk
== DESKTOP_ALL
)
429 screen_set_desktop(data
->desktop
.desk
);
432 void action_next_desktop(union ActionData
*data
)
436 d
= screen_desktop
+ 1;
437 if (d
>= screen_num_desktops
) {
438 if (!data
->nextprevdesktop
.wrap
) return;
441 screen_set_desktop(d
);
444 void action_previous_desktop(union ActionData
*data
)
448 d
= screen_desktop
- 1;
449 if (d
>= screen_num_desktops
) {
450 if (!data
->nextprevdesktop
.wrap
) return;
451 d
= screen_num_desktops
- 1;
453 screen_set_desktop(d
);
456 static void cur_row_col(guint
*r
, guint
*c
)
458 switch (screen_desktop_layout
.orientation
) {
459 case Orientation_Horz
:
460 switch (screen_desktop_layout
.start_corner
) {
462 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
463 *c
= screen_desktop
% screen_desktop_layout
.columns
;
465 case Corner_BottomLeft
:
466 *r
= screen_desktop_layout
.rows
- 1 -
467 screen_desktop
/ screen_desktop_layout
.columns
;
468 *c
= screen_desktop
% screen_desktop_layout
.columns
;
470 case Corner_TopRight
:
471 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
472 *c
= screen_desktop_layout
.columns
- 1 -
473 screen_desktop
% screen_desktop_layout
.columns
;
475 case Corner_BottomRight
:
476 *r
= screen_desktop_layout
.rows
- 1 -
477 screen_desktop
/ screen_desktop_layout
.columns
;
478 *c
= screen_desktop_layout
.columns
- 1 -
479 screen_desktop
% screen_desktop_layout
.columns
;
483 case Orientation_Vert
:
484 switch (screen_desktop_layout
.start_corner
) {
486 *r
= screen_desktop
% screen_desktop_layout
.rows
;
487 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
489 case Corner_BottomLeft
:
490 *r
= screen_desktop_layout
.rows
- 1 -
491 screen_desktop
% screen_desktop_layout
.rows
;
492 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
494 case Corner_TopRight
:
495 *r
= screen_desktop
% screen_desktop_layout
.rows
;
496 *c
= screen_desktop_layout
.columns
- 1 -
497 screen_desktop
/ screen_desktop_layout
.rows
;
499 case Corner_BottomRight
:
500 *r
= screen_desktop_layout
.rows
- 1 -
501 screen_desktop
% screen_desktop_layout
.rows
;
502 *c
= screen_desktop_layout
.columns
- 1 -
503 screen_desktop
/ screen_desktop_layout
.rows
;
510 static guint
translate_row_col(guint r
, guint c
)
512 switch (screen_desktop_layout
.orientation
) {
513 case Orientation_Horz
:
514 switch (screen_desktop_layout
.start_corner
) {
516 return r
* screen_desktop_layout
.columns
+ c
;
517 case Corner_BottomLeft
:
518 return (screen_desktop_layout
.rows
- 1 - r
) *
519 screen_desktop_layout
.columns
+ c
;
520 case Corner_TopRight
:
521 return r
* screen_desktop_layout
.columns
+
522 (screen_desktop_layout
.columns
- 1 - c
);
523 case Corner_BottomRight
:
524 return (screen_desktop_layout
.rows
- 1 - r
) *
525 screen_desktop_layout
.columns
+
526 (screen_desktop_layout
.columns
- 1 - c
);
528 case Orientation_Vert
:
529 switch (screen_desktop_layout
.start_corner
) {
531 return c
* screen_desktop_layout
.rows
+ r
;
532 case Corner_BottomLeft
:
533 return c
* screen_desktop_layout
.rows
+
534 (screen_desktop_layout
.rows
- 1 - r
);
535 case Corner_TopRight
:
536 return (screen_desktop_layout
.columns
- 1 - c
) *
537 screen_desktop_layout
.rows
+ r
;
538 case Corner_BottomRight
:
539 return (screen_desktop_layout
.columns
- 1 - c
) *
540 screen_desktop_layout
.rows
+
541 (screen_desktop_layout
.rows
- 1 - r
);
544 g_assert_not_reached();
548 void action_next_desktop_column(union ActionData
*data
)
554 d
= translate_row_col(r
, c
);
555 if (d
>= screen_num_desktops
) {
556 if (!data
->nextprevdesktop
.wrap
) return;
559 if (d
>= screen_num_desktops
)
561 d
= translate_row_col(r
, c
);
562 if (d
< screen_num_desktops
)
563 screen_set_desktop(d
);
566 void action_previous_desktop_column(union ActionData
*data
)
572 d
= translate_row_col(r
, c
);
573 if (d
>= screen_num_desktops
) {
574 if (!data
->nextprevdesktop
.wrap
) return;
575 c
= screen_desktop_layout
.columns
- 1;
577 if (d
>= screen_num_desktops
)
579 d
= translate_row_col(r
, c
);
580 if (d
< screen_num_desktops
)
581 screen_set_desktop(d
);
584 void action_next_desktop_row(union ActionData
*data
)
590 d
= translate_row_col(r
, c
);
591 if (d
>= screen_num_desktops
) {
592 if (!data
->nextprevdesktop
.wrap
) return;
595 if (d
>= screen_num_desktops
)
597 d
= translate_row_col(r
, c
);
598 if (d
< screen_num_desktops
)
599 screen_set_desktop(d
);
602 void action_previous_desktop_row(union ActionData
*data
)
608 d
= translate_row_col(r
, c
);
609 if (d
>= screen_num_desktops
) {
610 if (!data
->nextprevdesktop
.wrap
) return;
611 c
= screen_desktop_layout
.rows
- 1;
613 if (d
>= screen_num_desktops
)
615 d
= translate_row_col(r
, c
);
616 if (d
< screen_num_desktops
)
617 screen_set_desktop(d
);
620 void action_toggle_decorations(union ActionData
*data
)
622 Client
*c
= data
->client
.c
;
623 c
->disabled_decorations
= c
->disabled_decorations
? 0 : ~0;
624 client_setup_decor_and_functions(c
);
627 void action_move(union ActionData
*data
)
629 Client
*c
= data
->move
.c
;
630 int x
= data
->move
.x
;
631 int y
= data
->move
.y
;
633 if (!c
|| !client_normal(c
)) return;
635 dispatch_move(c
, &x
, &y
);
637 frame_frame_gravity(c
->frame
, &x
, &y
); /* get where the client should be */
638 client_configure(c
, Corner_TopLeft
, x
, y
, c
->area
.width
, c
->area
.height
,
639 TRUE
, data
->move
.final
);
642 void action_resize(union ActionData
*data
)
644 Client
*c
= data
->resize
.c
;
645 int w
= data
->resize
.x
;
646 int h
= data
->resize
.y
;
648 if (!c
|| c
->shaded
|| !client_normal(c
)) return;
650 dispatch_resize(c
, &w
, &h
, data
->resize
.corner
);
652 w
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
653 h
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
655 client_configure(c
, data
->resize
.corner
, c
->area
.x
, c
->area
.y
, w
, h
,
656 TRUE
, data
->resize
.final
);
659 void action_restart(union ActionData
*data
)
661 ob_restart_path
= data
->execute
.path
;
662 ob_shutdown
= ob_restart
= TRUE
;
665 void action_exit(union ActionData
*data
)
670 void action_showmenu(union ActionData
*data
)
672 g_message(__FUNCTION__
);
675 void action_cycle_windows(union ActionData
*data
)
677 static Client
*first
= NULL
;
678 static Client
*t
= NULL
;
679 static GList
*order
= NULL
;
680 GList
*it
, *start
, *list
;
682 if (data
->cycle
.cancel
) {
683 if (first
) client_focus(first
);
686 if (!first
) first
= focus_client
;
688 if (data
->cycle
.linear
)
691 if (!order
) order
= g_list_copy(focus_order
[screen_desktop
]);
694 start
= it
= g_list_find(list
, data
->cycle
.c
);
695 if (!start
) goto done_cycle
;
697 if (!data
->cycle
.final
) {
699 if (!start
) /* switched desktops or something? */
703 if (data
->cycle
.forward
) {
705 if (it
== NULL
) it
= list
;
708 if (it
== NULL
) it
= g_list_last(list
);
710 if (client_focus(it
->data
)) {
715 } while (it
!= start
);
717 if (t
) stacking_raise(t
);