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 } else if (!g_ascii_strcasecmp(name
, "sendtonextdesktop")) {
96 a
= action_new(action_send_to_next_desktop
);
97 a
->data
.sendtonextprev
.wrap
= FALSE
;
98 a
->data
.sendtonextprev
.follow
= TRUE
;
99 } else if (!g_ascii_strcasecmp(name
, "sendtonextdesktopwrap")) {
100 a
= action_new(action_send_to_next_desktop
);
101 a
->data
.sendtonextprev
.wrap
= TRUE
;
102 a
->data
.sendtonextprev
.follow
= TRUE
;
103 } else if (!g_ascii_strcasecmp(name
, "sendtopreviousdesktop")) {
104 a
= action_new(action_send_to_previous_desktop
);
105 a
->data
.sendtonextprev
.wrap
= FALSE
;
106 a
->data
.sendtonextprev
.follow
= TRUE
;
107 } else if (!g_ascii_strcasecmp(name
, "sendtopreviousdesktopwrap")) {
108 a
= action_new(action_send_to_previous_desktop
);
109 a
->data
.sendtonextprev
.wrap
= TRUE
;
110 a
->data
.sendtonextprev
.follow
= TRUE
;
111 } else if (!g_ascii_strcasecmp(name
, "desktop")) {
112 a
= action_new(action_desktop
);
113 } else if (!g_ascii_strcasecmp(name
, "nextdesktop")) {
114 a
= action_new(action_next_desktop
);
115 a
->data
.nextprevdesktop
.wrap
= FALSE
;
116 } else if (!g_ascii_strcasecmp(name
, "nextdesktopwrap")) {
117 a
= action_new(action_next_desktop
);
118 a
->data
.nextprevdesktop
.wrap
= TRUE
;
119 } else if (!g_ascii_strcasecmp(name
, "previousdesktop")) {
120 a
= action_new(action_previous_desktop
);
121 a
->data
.nextprevdesktop
.wrap
= FALSE
;
122 } else if (!g_ascii_strcasecmp(name
, "previousdesktopwrap")) {
123 a
= action_new(action_previous_desktop
);
124 a
->data
.nextprevdesktop
.wrap
= TRUE
;
125 } else if (!g_ascii_strcasecmp(name
, "nextdesktopcolumn")) {
126 a
= action_new(action_next_desktop_column
);
127 a
->data
.nextprevdesktop
.wrap
= FALSE
;
128 } else if (!g_ascii_strcasecmp(name
, "nextdesktopcolumnwrap")) {
129 a
= action_new(action_next_desktop_column
);
130 a
->data
.nextprevdesktop
.wrap
= TRUE
;
131 } else if (!g_ascii_strcasecmp(name
, "previousdesktopcolumn")) {
132 a
= action_new(action_previous_desktop_column
);
133 a
->data
.nextprevdesktop
.wrap
= FALSE
;
134 } else if (!g_ascii_strcasecmp(name
, "previousdesktopcolumnwrap")) {
135 a
= action_new(action_previous_desktop_column
);
136 a
->data
.nextprevdesktop
.wrap
= TRUE
;
137 } else if (!g_ascii_strcasecmp(name
, "nextdesktoprow")) {
138 a
= action_new(action_next_desktop_row
);
139 a
->data
.nextprevdesktop
.wrap
= FALSE
;
140 } else if (!g_ascii_strcasecmp(name
, "nextdesktoprowwrap")) {
141 a
= action_new(action_next_desktop_row
);
142 a
->data
.nextprevdesktop
.wrap
= TRUE
;
143 } else if (!g_ascii_strcasecmp(name
, "previousdesktoprow")) {
144 a
= action_new(action_previous_desktop_row
);
145 a
->data
.nextprevdesktop
.wrap
= FALSE
;
146 } else if (!g_ascii_strcasecmp(name
, "previousdesktoprowwrap")) {
147 a
= action_new(action_previous_desktop_row
);
148 a
->data
.nextprevdesktop
.wrap
= TRUE
;
149 } else if (!g_ascii_strcasecmp(name
, "toggledecorations")) {
150 a
= action_new(action_toggle_decorations
);
151 } else if (!g_ascii_strcasecmp(name
, "move")) {
152 a
= action_new(action_move
);
153 } else if (!g_ascii_strcasecmp(name
, "resize")) {
154 a
= action_new(action_resize
);
155 } else if (!g_ascii_strcasecmp(name
, "restart")) {
156 a
= action_new(action_restart
);
157 } else if (!g_ascii_strcasecmp(name
, "exit")) {
158 a
= action_new(action_exit
);
160 else if (!g_ascii_strcasecmp(name
, "showmenu")) {
161 a
= action_new(action_showmenu
);
167 void action_execute(union ActionData
*data
)
170 if (data
->execute
.path
)
171 if (!g_spawn_command_line_async(data
->execute
.path
, &e
)) {
172 g_warning("failed to execute '%s': %s",
173 data
->execute
.path
, e
->message
);
177 void action_focus(union ActionData
*data
)
180 client_focus(data
->client
.c
);
183 void action_unfocus (union ActionData
*data
)
186 client_unfocus(data
->client
.c
);
189 void action_iconify(union ActionData
*data
)
192 client_iconify(data
->client
.c
, TRUE
, TRUE
);
195 void action_focusraise(union ActionData
*data
)
197 if (data
->client
.c
) {
198 client_focus(data
->client
.c
);
199 stacking_raise(data
->client
.c
);
203 void action_raise(union ActionData
*data
)
206 stacking_raise(data
->client
.c
);
209 void action_unshaderaise(union ActionData
*data
)
211 if (data
->client
.c
) {
212 if (data
->client
.c
->shaded
)
213 client_shade(data
->client
.c
, FALSE
);
215 stacking_raise(data
->client
.c
);
219 void action_shadelower(union ActionData
*data
)
221 if (data
->client
.c
) {
222 if (data
->client
.c
->shaded
)
223 stacking_lower(data
->client
.c
);
225 client_shade(data
->client
.c
, TRUE
);
229 void action_lower(union ActionData
*data
)
232 stacking_lower(data
->client
.c
);
235 void action_close(union ActionData
*data
)
238 client_close(data
->client
.c
);
241 void action_kill(union ActionData
*data
)
244 client_kill(data
->client
.c
);
247 void action_shade(union ActionData
*data
)
250 client_shade(data
->client
.c
, TRUE
);
253 void action_unshade(union ActionData
*data
)
256 client_shade(data
->client
.c
, FALSE
);
259 void action_toggle_shade(union ActionData
*data
)
262 client_shade(data
->client
.c
, !data
->client
.c
->shaded
);
265 void action_toggle_omnipresent(union ActionData
*data
)
268 client_set_desktop(data
->client
.c
,
269 data
->client
.c
->desktop
== DESKTOP_ALL
?
270 screen_desktop
: DESKTOP_ALL
, FALSE
);
273 void action_move_relative_horz(union ActionData
*data
)
275 Client
*c
= data
->relative
.c
;
277 client_configure(c
, Corner_TopLeft
,
278 c
->area
.x
+ data
->relative
.delta
, c
->area
.y
,
279 c
->area
.width
, c
->area
.height
, TRUE
, TRUE
);
282 void action_move_relative_vert(union ActionData
*data
)
284 Client
*c
= data
->relative
.c
;
286 client_configure(c
, Corner_TopLeft
,
287 c
->area
.x
, c
->area
.y
+ data
->relative
.delta
,
288 c
->area
.width
, c
->area
.height
, TRUE
, TRUE
);
291 void action_resize_relative_horz(union ActionData
*data
)
293 Client
*c
= data
->relative
.c
;
295 client_configure(c
, Corner_TopLeft
, c
->area
.x
, c
->area
.y
,
296 c
->area
.width
+ data
->relative
.delta
,
297 c
->area
.height
, TRUE
, TRUE
);
300 void action_resize_relative_vert(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
, c
->area
.height
+ data
->relative
.delta
,
309 void action_maximize_full(union ActionData
*data
)
312 client_maximize(data
->client
.c
, TRUE
, 0, TRUE
);
315 void action_unmaximize_full(union ActionData
*data
)
318 client_maximize(data
->client
.c
, FALSE
, 0, TRUE
);
321 void action_toggle_maximize_full(union ActionData
*data
)
324 client_maximize(data
->client
.c
,
325 !(data
->client
.c
->max_horz
||
326 data
->client
.c
->max_vert
),
330 void action_maximize_horz(union ActionData
*data
)
333 client_maximize(data
->client
.c
, TRUE
, 1, TRUE
);
336 void action_unmaximize_horz(union ActionData
*data
)
339 client_maximize(data
->client
.c
, FALSE
, 1, TRUE
);
342 void action_toggle_maximize_horz(union ActionData
*data
)
345 client_maximize(data
->client
.c
, !data
->client
.c
->max_horz
, 1, TRUE
);
348 void action_maximize_vert(union ActionData
*data
)
351 client_maximize(data
->client
.c
, TRUE
, 2, TRUE
);
354 void action_unmaximize_vert(union ActionData
*data
)
357 client_maximize(data
->client
.c
, FALSE
, 2, TRUE
);
360 void action_toggle_maximize_vert(union ActionData
*data
)
363 client_maximize(data
->client
.c
, !data
->client
.c
->max_vert
, 2, TRUE
);
366 void action_send_to_desktop(union ActionData
*data
)
369 if (data
->sendto
.desktop
< screen_num_desktops
||
370 data
->sendto
.desktop
== DESKTOP_ALL
)
371 client_set_desktop(data
->sendto
.c
, data
->sendto
.desktop
, TRUE
);
374 void action_send_to_next_desktop(union ActionData
*data
)
378 if (!data
->sendto
.c
) return;
380 d
= screen_desktop
+ 1;
381 if (d
>= screen_num_desktops
) {
382 if (!data
->sendtonextprev
.wrap
) return;
385 client_set_desktop(data
->sendtonextprev
.c
, d
, data
->sendtonextprev
.follow
);
386 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
389 void action_send_to_previous_desktop(union ActionData
*data
)
393 if (!data
->sendto
.c
) return;
395 d
= screen_desktop
- 1;
396 if (d
>= screen_num_desktops
) {
397 if (!data
->sendtonextprev
.wrap
) return;
398 d
= screen_num_desktops
- 1;
400 client_set_desktop(data
->sendtonextprev
.c
, d
, data
->sendtonextprev
.follow
);
401 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
404 void action_desktop(union ActionData
*data
)
406 if (data
->desktop
.desk
< screen_num_desktops
||
407 data
->desktop
.desk
== DESKTOP_ALL
)
408 screen_set_desktop(data
->desktop
.desk
);
411 void action_next_desktop(union ActionData
*data
)
415 d
= screen_desktop
+ 1;
416 if (d
>= screen_num_desktops
) {
417 if (!data
->nextprevdesktop
.wrap
) return;
420 screen_set_desktop(d
);
423 void action_previous_desktop(union ActionData
*data
)
427 d
= screen_desktop
- 1;
428 if (d
>= screen_num_desktops
) {
429 if (!data
->nextprevdesktop
.wrap
) return;
430 d
= screen_num_desktops
- 1;
432 screen_set_desktop(d
);
435 static void cur_row_col(guint
*r
, guint
*c
)
437 switch (screen_desktop_layout
.orientation
) {
438 case Orientation_Horz
:
439 switch (screen_desktop_layout
.start_corner
) {
441 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
442 *c
= screen_desktop
% screen_desktop_layout
.columns
;
444 case Corner_BottomLeft
:
445 *r
= screen_desktop_layout
.rows
- 1 -
446 screen_desktop
/ screen_desktop_layout
.columns
;
447 *c
= screen_desktop
% screen_desktop_layout
.columns
;
450 case Corner_TopRight
:
451 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
452 *c
= screen_desktop_layout
.columns
- 1 -
453 screen_desktop
% screen_desktop_layout
.columns
;
455 case Corner_BottomRight
:
456 *r
= screen_desktop_layout
.rows
- 1 -
457 screen_desktop
/ screen_desktop_layout
.columns
;
458 *c
= screen_desktop_layout
.columns
- 1 -
459 screen_desktop
% screen_desktop_layout
.columns
;
463 case Orientation_Vert
:
464 switch (screen_desktop_layout
.start_corner
) {
466 *r
= screen_desktop
% screen_desktop_layout
.rows
;
467 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
469 case Corner_BottomLeft
:
470 *r
= screen_desktop_layout
.rows
- 1 -
471 screen_desktop
% screen_desktop_layout
.rows
;
472 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
475 case Corner_TopRight
:
476 *r
= screen_desktop
% screen_desktop_layout
.rows
;
477 *c
= screen_desktop_layout
.columns
- 1 -
478 screen_desktop
/ screen_desktop_layout
.rows
;
480 case Corner_BottomRight
:
481 *r
= screen_desktop_layout
.rows
- 1 -
482 screen_desktop
% screen_desktop_layout
.rows
;
483 *c
= screen_desktop_layout
.columns
- 1 -
484 screen_desktop
/ screen_desktop_layout
.rows
;
492 static guint
translate_row_col(guint r
, guint c
)
494 switch (screen_desktop_layout
.orientation
) {
495 case Orientation_Horz
:
496 switch (screen_desktop_layout
.start_corner
) {
498 return r
* screen_desktop_layout
.columns
+ c
;
499 case Corner_BottomLeft
:
500 return (screen_desktop_layout
.rows
- 1 - r
) *
501 screen_desktop_layout
.columns
+ c
;
502 case Corner_TopRight
:
503 return r
* screen_desktop_layout
.columns
+
504 (screen_desktop_layout
.columns
- 1 - c
);
505 case Corner_BottomRight
:
506 return (screen_desktop_layout
.rows
- 1 - r
) *
507 screen_desktop_layout
.columns
+
508 (screen_desktop_layout
.columns
- 1 - c
);
510 case Orientation_Vert
:
511 switch (screen_desktop_layout
.start_corner
) {
513 return c
* screen_desktop_layout
.rows
+ r
;
514 case Corner_BottomLeft
:
515 return c
* screen_desktop_layout
.rows
+
516 (screen_desktop_layout
.rows
- 1 - r
);
517 case Corner_TopRight
:
518 return (screen_desktop_layout
.columns
- 1 - c
) *
519 screen_desktop_layout
.rows
+ r
;
520 case Corner_BottomRight
:
521 return (screen_desktop_layout
.columns
- 1 - c
) *
522 screen_desktop_layout
.rows
+
523 (screen_desktop_layout
.rows
- 1 - r
);
526 g_assert_not_reached();
530 void action_next_desktop_column(union ActionData
*data
)
536 d
= translate_row_col(r
, c
);
537 if (d
>= screen_num_desktops
) {
538 if (!data
->nextprevdesktop
.wrap
) return;
541 if (d
>= screen_num_desktops
)
543 d
= translate_row_col(r
, c
);
544 if (d
< screen_num_desktops
)
545 screen_set_desktop(d
);
548 void action_previous_desktop_column(union ActionData
*data
)
554 d
= translate_row_col(r
, c
);
555 if (d
>= screen_num_desktops
) {
556 if (!data
->nextprevdesktop
.wrap
) return;
557 c
= screen_desktop_layout
.columns
- 1;
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_next_desktop_row(union ActionData
*data
)
572 d
= translate_row_col(r
, c
);
573 if (d
>= screen_num_desktops
) {
574 if (!data
->nextprevdesktop
.wrap
) return;
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_previous_desktop_row(union ActionData
*data
)
590 d
= translate_row_col(r
, c
);
591 if (d
>= screen_num_desktops
) {
592 if (!data
->nextprevdesktop
.wrap
) return;
593 c
= screen_desktop_layout
.rows
- 1;
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_toggle_decorations(union ActionData
*data
)
604 Client
*c
= data
->client
.c
;
605 c
->disabled_decorations
= c
->disabled_decorations
? 0 : ~0;
606 client_setup_decor_and_functions(c
);
609 void action_move(union ActionData
*data
)
611 Client
*c
= data
->move
.c
;
612 int x
= data
->move
.x
;
613 int y
= data
->move
.y
;
615 if (!c
|| !client_normal(c
)) return;
617 dispatch_move(c
, &x
, &y
);
619 frame_frame_gravity(c
->frame
, &x
, &y
); /* get where the client should be */
620 client_configure(c
, Corner_TopLeft
, x
, y
, c
->area
.width
, c
->area
.height
,
621 TRUE
, data
->move
.final
);
624 void action_resize(union ActionData
*data
)
626 Client
*c
= data
->resize
.c
;
627 int w
= data
->resize
.x
;
628 int h
= data
->resize
.y
;
630 if (!c
|| !client_normal(c
)) return;
632 /* XXX window snapping/struts */
634 dispatch_resize(c
, &w
, &h
, data
->resize
.corner
);
636 w
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
637 h
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
639 client_configure(c
, data
->resize
.corner
, c
->area
.x
, c
->area
.y
, w
, h
,
640 TRUE
, data
->resize
.final
);
643 void action_restart(union ActionData
*data
)
645 ob_restart_path
= data
->execute
.path
;
646 ob_shutdown
= ob_restart
= TRUE
;
649 void action_exit(union ActionData
*data
)
654 void action_showmenu(union ActionData
*data
)
656 g_message(__FUNCTION__
);