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
, "toggledecorations")) {
144 a
= action_new(action_toggle_decorations
);
145 } else if (!g_ascii_strcasecmp(name
, "move")) {
146 a
= action_new(action_move
);
147 } else if (!g_ascii_strcasecmp(name
, "resize")) {
148 a
= action_new(action_resize
);
149 } else if (!g_ascii_strcasecmp(name
, "restart")) {
150 a
= action_new(action_restart
);
151 } else if (!g_ascii_strcasecmp(name
, "exit")) {
152 a
= action_new(action_exit
);
157 void action_execute(union ActionData
*data
)
160 if (data
->execute
.path
)
161 if (!g_spawn_command_line_async(data
->execute
.path
, &e
)) {
162 g_warning("failed to execute '%s': %s",
163 data
->execute
.path
, e
->message
);
167 void action_focus(union ActionData
*data
)
170 client_focus(data
->client
.c
);
173 void action_unfocus (union ActionData
*data
)
176 client_unfocus(data
->client
.c
);
179 void action_iconify(union ActionData
*data
)
182 client_iconify(data
->client
.c
, TRUE
, TRUE
);
185 void action_focusraise(union ActionData
*data
)
187 if (data
->client
.c
) {
188 client_focus(data
->client
.c
);
189 stacking_raise(data
->client
.c
);
193 void action_raise(union ActionData
*data
)
196 stacking_raise(data
->client
.c
);
199 void action_lower(union ActionData
*data
)
202 stacking_lower(data
->client
.c
);
205 void action_close(union ActionData
*data
)
208 client_close(data
->client
.c
);
211 void action_kill(union ActionData
*data
)
214 client_kill(data
->client
.c
);
217 void action_shade(union ActionData
*data
)
220 client_shade(data
->client
.c
, TRUE
);
223 void action_unshade(union ActionData
*data
)
226 client_shade(data
->client
.c
, FALSE
);
229 void action_toggle_shade(union ActionData
*data
)
232 client_shade(data
->client
.c
, !data
->client
.c
->shaded
);
235 void action_toggle_omnipresent(union ActionData
*data
)
238 client_set_desktop(data
->client
.c
,
239 data
->client
.c
->desktop
== DESKTOP_ALL
?
240 screen_desktop
: DESKTOP_ALL
, FALSE
);
243 void action_move_relative_horz(union ActionData
*data
)
245 Client
*c
= data
->relative
.c
;
247 client_configure(c
, Corner_TopLeft
,
248 c
->area
.x
+ data
->relative
.delta
, c
->area
.y
,
249 c
->area
.width
, c
->area
.height
, TRUE
, TRUE
);
252 void action_move_relative_vert(union ActionData
*data
)
254 Client
*c
= data
->relative
.c
;
256 client_configure(c
, Corner_TopLeft
,
257 c
->area
.x
, c
->area
.y
+ data
->relative
.delta
,
258 c
->area
.width
, c
->area
.height
, TRUE
, TRUE
);
261 void action_resize_relative_horz(union ActionData
*data
)
263 Client
*c
= data
->relative
.c
;
265 client_configure(c
, Corner_TopLeft
, c
->area
.x
, c
->area
.y
,
266 c
->area
.width
+ data
->relative
.delta
,
267 c
->area
.height
, TRUE
, TRUE
);
270 void action_resize_relative_vert(union ActionData
*data
)
272 Client
*c
= data
->relative
.c
;
274 client_configure(c
, Corner_TopLeft
, c
->area
.x
, c
->area
.y
,
275 c
->area
.width
, c
->area
.height
+ data
->relative
.delta
,
279 void action_maximize_full(union ActionData
*data
)
282 client_maximize(data
->client
.c
, TRUE
, 0, TRUE
);
285 void action_unmaximize_full(union ActionData
*data
)
288 client_maximize(data
->client
.c
, FALSE
, 0, TRUE
);
291 void action_toggle_maximize_full(union ActionData
*data
)
294 client_maximize(data
->client
.c
,
295 !(data
->client
.c
->max_horz
||
296 data
->client
.c
->max_vert
),
300 void action_maximize_horz(union ActionData
*data
)
303 client_maximize(data
->client
.c
, TRUE
, 1, TRUE
);
306 void action_unmaximize_horz(union ActionData
*data
)
309 client_maximize(data
->client
.c
, FALSE
, 1, TRUE
);
312 void action_toggle_maximize_horz(union ActionData
*data
)
315 client_maximize(data
->client
.c
, !data
->client
.c
->max_horz
, 1, TRUE
);
318 void action_maximize_vert(union ActionData
*data
)
321 client_maximize(data
->client
.c
, TRUE
, 2, TRUE
);
324 void action_unmaximize_vert(union ActionData
*data
)
327 client_maximize(data
->client
.c
, FALSE
, 2, TRUE
);
330 void action_toggle_maximize_vert(union ActionData
*data
)
333 client_maximize(data
->client
.c
, !data
->client
.c
->max_vert
, 2, TRUE
);
336 void action_send_to_desktop(union ActionData
*data
)
339 if (data
->sendto
.desktop
< screen_num_desktops
||
340 data
->sendto
.desktop
== DESKTOP_ALL
)
341 client_set_desktop(data
->sendto
.c
, data
->sendto
.desktop
, TRUE
);
344 void action_send_to_next_desktop(union ActionData
*data
)
348 if (!data
->sendto
.c
) return;
350 d
= screen_desktop
+ 1;
351 if (d
>= screen_num_desktops
) {
352 if (!data
->sendtonextprev
.wrap
) return;
355 client_set_desktop(data
->sendtonextprev
.c
, d
, data
->sendtonextprev
.follow
);
356 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
359 void action_send_to_previous_desktop(union ActionData
*data
)
363 if (!data
->sendto
.c
) return;
365 d
= screen_desktop
- 1;
366 if (d
>= screen_num_desktops
) {
367 if (!data
->sendtonextprev
.wrap
) return;
368 d
= screen_num_desktops
- 1;
370 client_set_desktop(data
->sendtonextprev
.c
, d
, data
->sendtonextprev
.follow
);
371 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
374 void action_desktop(union ActionData
*data
)
376 if (data
->desktop
.desk
< screen_num_desktops
||
377 data
->desktop
.desk
== DESKTOP_ALL
)
378 screen_set_desktop(data
->desktop
.desk
);
381 void action_next_desktop(union ActionData
*data
)
385 d
= screen_desktop
+ 1;
386 if (d
>= screen_num_desktops
) {
387 if (!data
->nextprevdesktop
.wrap
) return;
390 screen_set_desktop(d
);
393 void action_previous_desktop(union ActionData
*data
)
397 d
= screen_desktop
- 1;
398 if (d
>= screen_num_desktops
) {
399 if (!data
->nextprevdesktop
.wrap
) return;
400 d
= screen_num_desktops
- 1;
402 screen_set_desktop(d
);
405 static void cur_row_col(guint
*r
, guint
*c
)
407 switch (screen_desktop_layout
.orientation
) {
408 case Orientation_Horz
:
409 switch (screen_desktop_layout
.start_corner
) {
411 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
412 *c
= screen_desktop
% screen_desktop_layout
.columns
;
414 case Corner_BottomLeft
:
415 *r
= screen_desktop_layout
.rows
- 1 -
416 screen_desktop
/ screen_desktop_layout
.columns
;
417 *c
= screen_desktop
% screen_desktop_layout
.columns
;
420 case Corner_TopRight
:
421 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
422 *c
= screen_desktop_layout
.columns
- 1 -
423 screen_desktop
% screen_desktop_layout
.columns
;
425 case Corner_BottomRight
:
426 *r
= screen_desktop_layout
.rows
- 1 -
427 screen_desktop
/ screen_desktop_layout
.columns
;
428 *c
= screen_desktop_layout
.columns
- 1 -
429 screen_desktop
% screen_desktop_layout
.columns
;
433 case Orientation_Vert
:
434 switch (screen_desktop_layout
.start_corner
) {
436 *r
= screen_desktop
% screen_desktop_layout
.rows
;
437 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
439 case Corner_BottomLeft
:
440 *r
= screen_desktop_layout
.rows
- 1 -
441 screen_desktop
% screen_desktop_layout
.rows
;
442 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
445 case Corner_TopRight
:
446 *r
= screen_desktop
% screen_desktop_layout
.rows
;
447 *c
= screen_desktop_layout
.columns
- 1 -
448 screen_desktop
/ screen_desktop_layout
.rows
;
450 case Corner_BottomRight
:
451 *r
= screen_desktop_layout
.rows
- 1 -
452 screen_desktop
% screen_desktop_layout
.rows
;
453 *c
= screen_desktop_layout
.columns
- 1 -
454 screen_desktop
/ screen_desktop_layout
.rows
;
462 static guint
translate_row_col(guint r
, guint c
)
464 switch (screen_desktop_layout
.orientation
) {
465 case Orientation_Horz
:
466 switch (screen_desktop_layout
.start_corner
) {
468 return r
* screen_desktop_layout
.columns
+ c
;
469 case Corner_BottomLeft
:
470 return (screen_desktop_layout
.rows
- 1 - r
) *
471 screen_desktop_layout
.columns
+ c
;
472 case Corner_TopRight
:
473 return r
* screen_desktop_layout
.columns
+
474 (screen_desktop_layout
.columns
- 1 - c
);
475 case Corner_BottomRight
:
476 return (screen_desktop_layout
.rows
- 1 - r
) *
477 screen_desktop_layout
.columns
+
478 (screen_desktop_layout
.columns
- 1 - c
);
480 case Orientation_Vert
:
481 switch (screen_desktop_layout
.start_corner
) {
483 return c
* screen_desktop_layout
.rows
+ r
;
484 case Corner_BottomLeft
:
485 return c
* screen_desktop_layout
.rows
+
486 (screen_desktop_layout
.rows
- 1 - r
);
487 case Corner_TopRight
:
488 return (screen_desktop_layout
.columns
- 1 - c
) *
489 screen_desktop_layout
.rows
+ r
;
490 case Corner_BottomRight
:
491 return (screen_desktop_layout
.columns
- 1 - c
) *
492 screen_desktop_layout
.rows
+
493 (screen_desktop_layout
.rows
- 1 - r
);
496 g_assert_not_reached();
500 void action_next_desktop_column(union ActionData
*data
)
506 d
= translate_row_col(r
, c
);
507 if (d
>= screen_num_desktops
) {
508 if (!data
->nextprevdesktop
.wrap
) return;
511 if (d
>= screen_num_desktops
)
513 d
= translate_row_col(r
, c
);
514 if (d
< screen_num_desktops
)
515 screen_set_desktop(d
);
518 void action_previous_desktop_column(union ActionData
*data
)
524 d
= translate_row_col(r
, c
);
525 if (d
>= screen_num_desktops
) {
526 if (!data
->nextprevdesktop
.wrap
) return;
527 c
= screen_desktop_layout
.columns
- 1;
529 if (d
>= screen_num_desktops
)
531 d
= translate_row_col(r
, c
);
532 if (d
< screen_num_desktops
)
533 screen_set_desktop(d
);
536 void action_next_desktop_row(union ActionData
*data
)
542 d
= translate_row_col(r
, c
);
543 if (d
>= screen_num_desktops
) {
544 if (!data
->nextprevdesktop
.wrap
) return;
547 if (d
>= screen_num_desktops
)
549 d
= translate_row_col(r
, c
);
550 if (d
< screen_num_desktops
)
551 screen_set_desktop(d
);
554 void action_previous_desktop_row(union ActionData
*data
)
560 d
= translate_row_col(r
, c
);
561 if (d
>= screen_num_desktops
) {
562 if (!data
->nextprevdesktop
.wrap
) return;
563 c
= screen_desktop_layout
.rows
- 1;
565 if (d
>= screen_num_desktops
)
567 d
= translate_row_col(r
, c
);
568 if (d
< screen_num_desktops
)
569 screen_set_desktop(d
);
572 void action_toggle_decorations(union ActionData
*data
)
574 Client
*c
= data
->client
.c
;
575 c
->disabled_decorations
= c
->disabled_decorations
? 0 : ~0;
576 client_setup_decor_and_functions(c
);
579 void action_move(union ActionData
*data
)
581 Client
*c
= data
->move
.c
;
582 int x
= data
->move
.x
;
583 int y
= data
->move
.y
;
585 if (!c
|| !client_normal(c
)) return;
587 dispatch_move(c
, &x
, &y
);
589 frame_frame_gravity(c
->frame
, &x
, &y
); /* get where the client should be */
590 client_configure(c
, Corner_TopLeft
, x
, y
, c
->area
.width
, c
->area
.height
,
591 TRUE
, data
->move
.final
);
594 void action_resize(union ActionData
*data
)
596 Client
*c
= data
->resize
.c
;
597 int w
= data
->resize
.x
;
598 int h
= data
->resize
.y
;
600 if (!c
|| !client_normal(c
)) return;
602 dispatch_resize(c
, &w
, &h
, data
->resize
.corner
);
604 w
-= c
->frame
->size
.left
+ c
->frame
->size
.right
;
605 h
-= c
->frame
->size
.top
+ c
->frame
->size
.bottom
;
606 client_configure(c
, data
->resize
.corner
, c
->area
.x
, c
->area
.y
, w
, h
,
607 TRUE
, data
->resize
.final
);
610 void action_restart(union ActionData
*data
)
612 ob_restart_path
= data
->execute
.path
;
613 ob_shutdown
= ob_restart
= TRUE
;
616 void action_exit(union ActionData
*data
)