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
, "shade")) {
56 a
= action_new(action_shade
);
57 } else if (!g_ascii_strcasecmp(name
, "unshade")) {
58 a
= action_new(action_unshade
);
59 } else if (!g_ascii_strcasecmp(name
, "toggleshade")) {
60 a
= action_new(action_toggle_shade
);
61 } else if (!g_ascii_strcasecmp(name
, "toggleomnipresent")) {
62 a
= action_new(action_toggle_omnipresent
);
63 } else if (!g_ascii_strcasecmp(name
, "moverelativehorz")) {
64 a
= action_new(action_move_relative_horz
);
65 } else if (!g_ascii_strcasecmp(name
, "moverelativevert")) {
66 a
= action_new(action_move_relative_vert
);
67 } else if (!g_ascii_strcasecmp(name
, "resizerelativehorz")) {
68 a
= action_new(action_resize_relative_horz
);
69 } else if (!g_ascii_strcasecmp(name
, "resizerelativevert")) {
70 a
= action_new(action_resize_relative_vert
);
71 } else if (!g_ascii_strcasecmp(name
, "maximizefull")) {
72 a
= action_new(action_maximize_full
);
73 } else if (!g_ascii_strcasecmp(name
, "unmaximizefull")) {
74 a
= action_new(action_unmaximize_full
);
75 } else if (!g_ascii_strcasecmp(name
, "togglemaximizefull")) {
76 a
= action_new(action_toggle_maximize_full
);
77 } else if (!g_ascii_strcasecmp(name
, "maximizehorz")) {
78 a
= action_new(action_maximize_horz
);
79 } else if (!g_ascii_strcasecmp(name
, "unmaximizehorz")) {
80 a
= action_new(action_unmaximize_horz
);
81 } else if (!g_ascii_strcasecmp(name
, "togglemaximizehorz")) {
82 a
= action_new(action_toggle_maximize_horz
);
83 } else if (!g_ascii_strcasecmp(name
, "maximizevert")) {
84 a
= action_new(action_maximize_vert
);
85 } else if (!g_ascii_strcasecmp(name
, "unmaximizevert")) {
86 a
= action_new(action_unmaximize_vert
);
87 } else if (!g_ascii_strcasecmp(name
, "togglemaximizevert")) {
88 a
= action_new(action_toggle_maximize_vert
);
89 } else if (!g_ascii_strcasecmp(name
, "sendtonextdesktop")) {
90 a
= action_new(action_send_to_next_desktop
);
91 a
->data
.sendtonextprev
.wrap
= FALSE
;
92 a
->data
.sendtonextprev
.follow
= TRUE
;
93 } else if (!g_ascii_strcasecmp(name
, "sendtonextdesktopwrap")) {
94 a
= action_new(action_send_to_next_desktop
);
95 a
->data
.sendtonextprev
.wrap
= TRUE
;
96 a
->data
.sendtonextprev
.follow
= TRUE
;
97 } else if (!g_ascii_strcasecmp(name
, "sendtopreviousdesktop")) {
98 a
= action_new(action_send_to_previous_desktop
);
99 a
->data
.sendtonextprev
.wrap
= FALSE
;
100 a
->data
.sendtonextprev
.follow
= TRUE
;
101 } else if (!g_ascii_strcasecmp(name
, "sendtopreviousdesktopwrap")) {
102 a
= action_new(action_send_to_previous_desktop
);
103 a
->data
.sendtonextprev
.wrap
= TRUE
;
104 a
->data
.sendtonextprev
.follow
= TRUE
;
105 } else if (!g_ascii_strcasecmp(name
, "desktop")) {
106 a
= action_new(action_desktop
);
107 } else if (!g_ascii_strcasecmp(name
, "nextdesktop")) {
108 a
= action_new(action_next_desktop
);
109 a
->data
.nextprevdesktop
.wrap
= FALSE
;
110 } else if (!g_ascii_strcasecmp(name
, "nextdesktopwrap")) {
111 a
= action_new(action_next_desktop
);
112 a
->data
.nextprevdesktop
.wrap
= TRUE
;
113 } else if (!g_ascii_strcasecmp(name
, "previousdesktop")) {
114 a
= action_new(action_previous_desktop
);
115 a
->data
.nextprevdesktop
.wrap
= FALSE
;
116 } else if (!g_ascii_strcasecmp(name
, "previousdesktopwrap")) {
117 a
= action_new(action_previous_desktop
);
118 a
->data
.nextprevdesktop
.wrap
= TRUE
;
119 } else if (!g_ascii_strcasecmp(name
, "nextdesktopcolumn")) {
120 a
= action_new(action_next_desktop_column
);
121 a
->data
.nextprevdesktop
.wrap
= FALSE
;
122 } else if (!g_ascii_strcasecmp(name
, "nextdesktopcolumnwrap")) {
123 a
= action_new(action_next_desktop_column
);
124 a
->data
.nextprevdesktop
.wrap
= TRUE
;
125 } else if (!g_ascii_strcasecmp(name
, "previousdesktopcolumn")) {
126 a
= action_new(action_previous_desktop_column
);
127 a
->data
.nextprevdesktop
.wrap
= FALSE
;
128 } else if (!g_ascii_strcasecmp(name
, "previousdesktopcolumnwrap")) {
129 a
= action_new(action_previous_desktop_column
);
130 a
->data
.nextprevdesktop
.wrap
= TRUE
;
131 } else if (!g_ascii_strcasecmp(name
, "nextdesktoprow")) {
132 a
= action_new(action_next_desktop_row
);
133 a
->data
.nextprevdesktop
.wrap
= FALSE
;
134 } else if (!g_ascii_strcasecmp(name
, "nextdesktoprowwrap")) {
135 a
= action_new(action_next_desktop_row
);
136 a
->data
.nextprevdesktop
.wrap
= TRUE
;
137 } else if (!g_ascii_strcasecmp(name
, "previousdesktoprow")) {
138 a
= action_new(action_previous_desktop_row
);
139 a
->data
.nextprevdesktop
.wrap
= FALSE
;
140 } else if (!g_ascii_strcasecmp(name
, "previousdesktoprowwrap")) {
141 a
= action_new(action_previous_desktop_row
);
142 a
->data
.nextprevdesktop
.wrap
= TRUE
;
143 } else if (!g_ascii_strcasecmp(name
, "move")) {
144 a
= action_new(action_move
);
145 } else if (!g_ascii_strcasecmp(name
, "resize")) {
146 a
= action_new(action_resize
);
147 } else if (!g_ascii_strcasecmp(name
, "restart")) {
148 a
= action_new(action_restart
);
149 } else if (!g_ascii_strcasecmp(name
, "exit")) {
150 a
= action_new(action_exit
);
155 void action_execute(union ActionData
*data
)
158 if (data
->execute
.path
)
159 if (!g_spawn_command_line_async(data
->execute
.path
, &e
)) {
160 g_warning("failed to execute '%s': %s",
161 data
->execute
.path
, e
->message
);
165 void action_focus(union ActionData
*data
)
168 client_focus(data
->client
.c
);
171 void action_unfocus (union ActionData
*data
)
174 client_unfocus(data
->client
.c
);
177 void action_iconify(union ActionData
*data
)
180 client_iconify(data
->client
.c
, TRUE
, TRUE
);
183 void action_focusraise(union ActionData
*data
)
185 if (data
->client
.c
) {
186 client_focus(data
->client
.c
);
187 stacking_raise(data
->client
.c
);
191 void action_raise(union ActionData
*data
)
194 stacking_raise(data
->client
.c
);
197 void action_lower(union ActionData
*data
)
200 stacking_lower(data
->client
.c
);
203 void action_close(union ActionData
*data
)
206 client_close(data
->client
.c
);
209 void action_kill(union ActionData
*data
)
212 client_kill(data
->client
.c
);
215 void action_shade(union ActionData
*data
)
218 client_shade(data
->client
.c
, TRUE
);
221 void action_unshade(union ActionData
*data
)
224 client_shade(data
->client
.c
, FALSE
);
227 void action_toggle_shade(union ActionData
*data
)
230 client_shade(data
->client
.c
, !data
->client
.c
->shaded
);
233 void action_toggle_omnipresent(union ActionData
*data
)
236 client_set_desktop(data
->client
.c
,
237 data
->client
.c
->desktop
== DESKTOP_ALL
?
238 screen_desktop
: DESKTOP_ALL
, FALSE
);
241 void action_move_relative_horz(union ActionData
*data
)
243 Client
*c
= data
->relative
.c
;
245 client_configure(c
, Corner_TopLeft
,
246 c
->area
.x
+ data
->relative
.delta
, c
->area
.y
,
247 c
->area
.width
, c
->area
.height
, TRUE
, TRUE
);
250 void action_move_relative_vert(union ActionData
*data
)
252 Client
*c
= data
->relative
.c
;
254 client_configure(c
, Corner_TopLeft
,
255 c
->area
.x
, c
->area
.y
+ data
->relative
.delta
,
256 c
->area
.width
, c
->area
.height
, TRUE
, TRUE
);
259 void action_resize_relative_horz(union ActionData
*data
)
261 Client
*c
= data
->relative
.c
;
263 client_configure(c
, Corner_TopLeft
, c
->area
.x
, c
->area
.y
,
264 c
->area
.width
+ data
->relative
.delta
,
265 c
->area
.height
, TRUE
, TRUE
);
268 void action_resize_relative_vert(union ActionData
*data
)
270 Client
*c
= data
->relative
.c
;
272 client_configure(c
, Corner_TopLeft
, c
->area
.x
, c
->area
.y
,
273 c
->area
.width
, c
->area
.height
+ data
->relative
.delta
,
277 void action_maximize_full(union ActionData
*data
)
280 client_maximize(data
->client
.c
, TRUE
, 0, TRUE
);
283 void action_unmaximize_full(union ActionData
*data
)
286 client_maximize(data
->client
.c
, FALSE
, 0, TRUE
);
289 void action_toggle_maximize_full(union ActionData
*data
)
292 client_maximize(data
->client
.c
,
293 !(data
->client
.c
->max_horz
||
294 data
->client
.c
->max_vert
),
298 void action_maximize_horz(union ActionData
*data
)
301 client_maximize(data
->client
.c
, TRUE
, 1, TRUE
);
304 void action_unmaximize_horz(union ActionData
*data
)
307 client_maximize(data
->client
.c
, FALSE
, 1, TRUE
);
310 void action_toggle_maximize_horz(union ActionData
*data
)
313 client_maximize(data
->client
.c
, !data
->client
.c
->max_horz
, 1, TRUE
);
316 void action_maximize_vert(union ActionData
*data
)
319 client_maximize(data
->client
.c
, TRUE
, 2, TRUE
);
322 void action_unmaximize_vert(union ActionData
*data
)
325 client_maximize(data
->client
.c
, FALSE
, 2, TRUE
);
328 void action_toggle_maximize_vert(union ActionData
*data
)
331 client_maximize(data
->client
.c
, !data
->client
.c
->max_vert
, 2, TRUE
);
334 void action_send_to_desktop(union ActionData
*data
)
337 if (data
->sendto
.desktop
< screen_num_desktops
||
338 data
->sendto
.desktop
== DESKTOP_ALL
)
339 client_set_desktop(data
->sendto
.c
, data
->sendto
.desktop
, TRUE
);
342 void action_send_to_next_desktop(union ActionData
*data
)
346 if (!data
->sendto
.c
) return;
348 d
= screen_desktop
+ 1;
349 if (d
>= screen_num_desktops
) {
350 if (!data
->sendtonextprev
.wrap
) return;
353 client_set_desktop(data
->sendtonextprev
.c
, d
, data
->sendtonextprev
.follow
);
354 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
357 void action_send_to_previous_desktop(union ActionData
*data
)
361 if (!data
->sendto
.c
) return;
363 d
= screen_desktop
- 1;
364 if (d
>= screen_num_desktops
) {
365 if (!data
->sendtonextprev
.wrap
) return;
366 d
= screen_num_desktops
- 1;
368 client_set_desktop(data
->sendtonextprev
.c
, d
, data
->sendtonextprev
.follow
);
369 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
372 void action_desktop(union ActionData
*data
)
374 if (data
->desktop
.desk
< screen_num_desktops
||
375 data
->desktop
.desk
== DESKTOP_ALL
)
376 screen_set_desktop(data
->desktop
.desk
);
379 void action_next_desktop(union ActionData
*data
)
383 d
= screen_desktop
+ 1;
384 if (d
>= screen_num_desktops
) {
385 if (!data
->nextprevdesktop
.wrap
) return;
388 screen_set_desktop(d
);
391 void action_previous_desktop(union ActionData
*data
)
395 d
= screen_desktop
- 1;
396 if (d
>= screen_num_desktops
) {
397 if (!data
->nextprevdesktop
.wrap
) return;
398 d
= screen_num_desktops
- 1;
400 screen_set_desktop(d
);
403 static void cur_row_col(guint
*r
, guint
*c
)
405 switch (screen_desktop_layout
.orientation
) {
406 case Orientation_Horz
:
407 switch (screen_desktop_layout
.start_corner
) {
409 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
410 *c
= screen_desktop
% screen_desktop_layout
.columns
;
412 case Corner_BottomLeft
:
413 *r
= screen_desktop_layout
.rows
- 1 -
414 screen_desktop
/ screen_desktop_layout
.columns
;
415 *c
= screen_desktop
% screen_desktop_layout
.columns
;
418 case Corner_TopRight
:
419 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
420 *c
= screen_desktop_layout
.columns
- 1 -
421 screen_desktop
% screen_desktop_layout
.columns
;
423 case Corner_BottomRight
:
424 *r
= screen_desktop_layout
.rows
- 1 -
425 screen_desktop
/ screen_desktop_layout
.columns
;
426 *c
= screen_desktop_layout
.columns
- 1 -
427 screen_desktop
% screen_desktop_layout
.columns
;
431 case Orientation_Vert
:
432 switch (screen_desktop_layout
.start_corner
) {
434 *r
= screen_desktop
% screen_desktop_layout
.rows
;
435 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
437 case Corner_BottomLeft
:
438 *r
= screen_desktop_layout
.rows
- 1 -
439 screen_desktop
% screen_desktop_layout
.rows
;
440 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
443 case Corner_TopRight
:
444 *r
= screen_desktop
% screen_desktop_layout
.rows
;
445 *c
= screen_desktop_layout
.columns
- 1 -
446 screen_desktop
/ screen_desktop_layout
.rows
;
448 case Corner_BottomRight
:
449 *r
= screen_desktop_layout
.rows
- 1 -
450 screen_desktop
% screen_desktop_layout
.rows
;
451 *c
= screen_desktop_layout
.columns
- 1 -
452 screen_desktop
/ screen_desktop_layout
.rows
;
460 static guint
translate_row_col(guint r
, guint c
)
462 switch (screen_desktop_layout
.orientation
) {
463 case Orientation_Horz
:
464 switch (screen_desktop_layout
.start_corner
) {
466 return r
* screen_desktop_layout
.columns
+ c
;
467 case Corner_BottomLeft
:
468 return (screen_desktop_layout
.rows
- 1 - r
) *
469 screen_desktop_layout
.columns
+ c
;
470 case Corner_TopRight
:
471 return r
* screen_desktop_layout
.columns
+
472 (screen_desktop_layout
.columns
- 1 - c
);
473 case Corner_BottomRight
:
474 return (screen_desktop_layout
.rows
- 1 - r
) *
475 screen_desktop_layout
.columns
+
476 (screen_desktop_layout
.columns
- 1 - c
);
478 case Orientation_Vert
:
479 switch (screen_desktop_layout
.start_corner
) {
481 return c
* screen_desktop_layout
.rows
+ r
;
482 case Corner_BottomLeft
:
483 return c
* screen_desktop_layout
.rows
+
484 (screen_desktop_layout
.rows
- 1 - r
);
485 case Corner_TopRight
:
486 return (screen_desktop_layout
.columns
- 1 - c
) *
487 screen_desktop_layout
.rows
+ r
;
488 case Corner_BottomRight
:
489 return (screen_desktop_layout
.columns
- 1 - c
) *
490 screen_desktop_layout
.rows
+
491 (screen_desktop_layout
.rows
- 1 - r
);
494 g_assert_not_reached();
498 void action_next_desktop_column(union ActionData
*data
)
504 d
= translate_row_col(r
, c
);
505 if (d
>= screen_num_desktops
) {
506 if (!data
->nextprevdesktop
.wrap
) return;
509 if (d
>= screen_num_desktops
)
511 d
= translate_row_col(r
, c
);
512 if (d
< screen_num_desktops
)
513 screen_set_desktop(d
);
516 void action_previous_desktop_column(union ActionData
*data
)
522 d
= translate_row_col(r
, c
);
523 if (d
>= screen_num_desktops
) {
524 if (!data
->nextprevdesktop
.wrap
) return;
525 c
= screen_desktop_layout
.columns
- 1;
527 if (d
>= screen_num_desktops
)
529 d
= translate_row_col(r
, c
);
530 if (d
< screen_num_desktops
)
531 screen_set_desktop(d
);
534 void action_next_desktop_row(union ActionData
*data
)
540 d
= translate_row_col(r
, c
);
541 if (d
>= screen_num_desktops
) {
542 if (!data
->nextprevdesktop
.wrap
) return;
545 if (d
>= screen_num_desktops
)
547 d
= translate_row_col(r
, c
);
548 if (d
< screen_num_desktops
)
549 screen_set_desktop(d
);
552 void action_previous_desktop_row(union ActionData
*data
)
558 d
= translate_row_col(r
, c
);
559 if (d
>= screen_num_desktops
) {
560 if (!data
->nextprevdesktop
.wrap
) return;
561 c
= screen_desktop_layout
.rows
- 1;
563 if (d
>= screen_num_desktops
)
565 d
= translate_row_col(r
, c
);
566 if (d
< screen_num_desktops
)
567 screen_set_desktop(d
);
570 void action_toggle_decorations(union ActionData
*data
)
572 Client
*c
= data
->client
.c
;
573 c
->disabled_decorations
= c
->disabled_decorations
? 0 : ~0;
574 client_setup_decor_and_functions(c
);
577 void action_move(union ActionData
*data
)
579 Client
*c
= data
->move
.c
;
580 int x
= data
->move
.x
;
581 int y
= data
->move
.y
;
583 if (!c
|| !client_normal(c
)) return;
585 dispatch_move(c
, &x
, &y
);
587 frame_frame_gravity(c
->frame
, &x
, &y
); /* get where the client should be */
588 client_configure(c
, Corner_TopLeft
, x
, y
, c
->area
.width
, c
->area
.height
,
589 TRUE
, data
->move
.final
);
592 void action_resize(union ActionData
*data
)
594 Client
*c
= data
->resize
.c
;
595 int w
= data
->resize
.x
- c
->frame
->size
.left
- c
->frame
->size
.right
;
596 int h
= data
->resize
.y
- c
->frame
->size
.top
- c
->frame
->size
.bottom
;
598 if (!c
|| !client_normal(c
)) return;
600 /* XXX window snapping/struts */
602 client_configure(c
, data
->resize
.corner
, c
->area
.x
, c
->area
.y
, w
, h
,
603 TRUE
, data
->resize
.final
);
606 void action_restart(union ActionData
*data
)
608 ob_restart_path
= data
->execute
.path
;
609 ob_shutdown
= ob_restart
= TRUE
;
612 void action_exit(union ActionData
*data
)