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
, "moverelative")) {
64 a
= action_new(action_move_relative
);
65 } else if (!g_ascii_strcasecmp(name
, "resizerelative")) {
66 a
= action_new(action_resize_relative
);
67 } else if (!g_ascii_strcasecmp(name
, "maximizefull")) {
68 a
= action_new(action_maximize_full
);
69 } else if (!g_ascii_strcasecmp(name
, "unmaximizefull")) {
70 a
= action_new(action_unmaximize_full
);
71 } else if (!g_ascii_strcasecmp(name
, "togglemaximizefull")) {
72 a
= action_new(action_toggle_maximize_full
);
73 } else if (!g_ascii_strcasecmp(name
, "maximizehorz")) {
74 a
= action_new(action_maximize_horz
);
75 } else if (!g_ascii_strcasecmp(name
, "unmaximizehorz")) {
76 a
= action_new(action_unmaximize_horz
);
77 } else if (!g_ascii_strcasecmp(name
, "togglemaximizehorz")) {
78 a
= action_new(action_toggle_maximize_horz
);
79 } else if (!g_ascii_strcasecmp(name
, "maximizevert")) {
80 a
= action_new(action_maximize_vert
);
81 } else if (!g_ascii_strcasecmp(name
, "unmaximizevert")) {
82 a
= action_new(action_unmaximize_vert
);
83 } else if (!g_ascii_strcasecmp(name
, "togglemaximizevert")) {
84 a
= action_new(action_toggle_maximize_vert
);
85 } else if (!g_ascii_strcasecmp(name
, "sendtonextdesktop")) {
86 a
= action_new(action_send_to_next_desktop
);
87 a
->data
.sendtonextprev
.wrap
= FALSE
;
88 a
->data
.sendtonextprev
.follow
= TRUE
;
89 } else if (!g_ascii_strcasecmp(name
, "sendtonextdesktopwrap")) {
90 a
= action_new(action_send_to_next_desktop
);
91 a
->data
.sendtonextprev
.wrap
= TRUE
;
92 a
->data
.sendtonextprev
.follow
= TRUE
;
93 } else if (!g_ascii_strcasecmp(name
, "sendtopreviousdesktop")) {
94 a
= action_new(action_send_to_previous_desktop
);
95 a
->data
.sendtonextprev
.wrap
= FALSE
;
96 a
->data
.sendtonextprev
.follow
= TRUE
;
97 } else if (!g_ascii_strcasecmp(name
, "sendtopreviousdesktopwrap")) {
98 a
= action_new(action_send_to_previous_desktop
);
99 a
->data
.sendtonextprev
.wrap
= TRUE
;
100 a
->data
.sendtonextprev
.follow
= TRUE
;
101 } else if (!g_ascii_strcasecmp(name
, "desktop")) {
102 a
= action_new(action_desktop
);
103 } else if (!g_ascii_strcasecmp(name
, "nextdesktop")) {
104 a
= action_new(action_next_desktop
);
105 a
->data
.nextprevdesktop
.wrap
= FALSE
;
106 } else if (!g_ascii_strcasecmp(name
, "nextdesktopwrap")) {
107 a
= action_new(action_next_desktop
);
108 a
->data
.nextprevdesktop
.wrap
= TRUE
;
109 } else if (!g_ascii_strcasecmp(name
, "previousdesktop")) {
110 a
= action_new(action_previous_desktop
);
111 a
->data
.nextprevdesktop
.wrap
= FALSE
;
112 } else if (!g_ascii_strcasecmp(name
, "previousdesktopwrap")) {
113 a
= action_new(action_previous_desktop
);
114 a
->data
.nextprevdesktop
.wrap
= TRUE
;
115 } else if (!g_ascii_strcasecmp(name
, "nextdesktopcolumn")) {
116 a
= action_new(action_next_desktop_column
);
117 a
->data
.nextprevdesktop
.wrap
= FALSE
;
118 } else if (!g_ascii_strcasecmp(name
, "nextdesktopcolumnwrap")) {
119 a
= action_new(action_next_desktop_column
);
120 a
->data
.nextprevdesktop
.wrap
= TRUE
;
121 } else if (!g_ascii_strcasecmp(name
, "previousdesktopcolumn")) {
122 a
= action_new(action_previous_desktop_column
);
123 a
->data
.nextprevdesktop
.wrap
= FALSE
;
124 } else if (!g_ascii_strcasecmp(name
, "previousdesktopcolumnwrap")) {
125 a
= action_new(action_previous_desktop_column
);
126 a
->data
.nextprevdesktop
.wrap
= TRUE
;
127 } else if (!g_ascii_strcasecmp(name
, "nextdesktoprow")) {
128 a
= action_new(action_next_desktop_row
);
129 a
->data
.nextprevdesktop
.wrap
= FALSE
;
130 } else if (!g_ascii_strcasecmp(name
, "nextdesktoprowwrap")) {
131 a
= action_new(action_next_desktop_row
);
132 a
->data
.nextprevdesktop
.wrap
= TRUE
;
133 } else if (!g_ascii_strcasecmp(name
, "previousdesktoprow")) {
134 a
= action_new(action_previous_desktop_row
);
135 a
->data
.nextprevdesktop
.wrap
= FALSE
;
136 } else if (!g_ascii_strcasecmp(name
, "previousdesktoprowwrap")) {
137 a
= action_new(action_previous_desktop_row
);
138 a
->data
.nextprevdesktop
.wrap
= TRUE
;
139 } else if (!g_ascii_strcasecmp(name
, "move")) {
140 a
= action_new(action_move
);
141 } else if (!g_ascii_strcasecmp(name
, "resize")) {
142 a
= action_new(action_resize
);
143 } else if (!g_ascii_strcasecmp(name
, "restart")) {
144 a
= action_new(action_restart
);
145 } else if (!g_ascii_strcasecmp(name
, "exit")) {
146 a
= action_new(action_exit
);
151 void action_execute(union ActionData
*data
)
154 if (data
->execute
.path
)
155 if (!g_spawn_command_line_async(data
->execute
.path
, &e
)) {
156 g_warning("failed to execute '%s': %s",
157 data
->execute
.path
, e
->message
);
161 void action_focus(union ActionData
*data
)
164 client_focus(data
->client
.c
);
167 void action_unfocus (union ActionData
*data
)
170 client_unfocus(data
->client
.c
);
173 void action_iconify(union ActionData
*data
)
176 client_iconify(data
->client
.c
, TRUE
, TRUE
);
179 void action_focusraise(union ActionData
*data
)
181 if (data
->client
.c
) {
182 client_focus(data
->client
.c
);
183 stacking_raise(data
->client
.c
);
187 void action_raise(union ActionData
*data
)
190 stacking_raise(data
->client
.c
);
193 void action_lower(union ActionData
*data
)
196 stacking_lower(data
->client
.c
);
199 void action_close(union ActionData
*data
)
202 client_close(data
->client
.c
);
205 void action_kill(union ActionData
*data
)
208 client_kill(data
->client
.c
);
211 void action_shade(union ActionData
*data
)
214 client_shade(data
->client
.c
, TRUE
);
217 void action_unshade(union ActionData
*data
)
220 client_shade(data
->client
.c
, FALSE
);
223 void action_toggle_shade(union ActionData
*data
)
226 client_shade(data
->client
.c
, !data
->client
.c
->shaded
);
229 void action_toggle_omnipresent(union ActionData
*data
)
232 client_set_desktop(data
->client
.c
,
233 data
->client
.c
->desktop
== DESKTOP_ALL
?
234 screen_desktop
: DESKTOP_ALL
);
237 void action_move_relative(union ActionData
*data
)
239 Client
*c
= data
->relative
.c
;
241 client_configure(c
, Corner_TopLeft
,
242 c
->area
.x
+ data
->relative
.dx
,
243 c
->area
.y
+ data
->relative
.dy
,
244 c
->area
.width
, c
->area
.height
, TRUE
, TRUE
);
247 void action_resize_relative(union ActionData
*data
)
249 Client
*c
= data
->relative
.c
;
251 client_configure(c
, Corner_TopLeft
, c
->area
.x
, c
->area
.y
,
252 c
->area
.width
+ data
->relative
.dx
,
253 c
->area
.height
+ data
->relative
.dy
, TRUE
, TRUE
);
256 void action_maximize_full(union ActionData
*data
)
259 client_maximize(data
->client
.c
, TRUE
, 0, TRUE
);
262 void action_unmaximize_full(union ActionData
*data
)
265 client_maximize(data
->client
.c
, FALSE
, 0, TRUE
);
268 void action_toggle_maximize_full(union ActionData
*data
)
271 client_maximize(data
->client
.c
,
272 !(data
->client
.c
->max_horz
||
273 data
->client
.c
->max_vert
),
277 void action_maximize_horz(union ActionData
*data
)
280 client_maximize(data
->client
.c
, TRUE
, 1, TRUE
);
283 void action_unmaximize_horz(union ActionData
*data
)
286 client_maximize(data
->client
.c
, FALSE
, 1, TRUE
);
289 void action_toggle_maximize_horz(union ActionData
*data
)
292 client_maximize(data
->client
.c
, !data
->client
.c
->max_horz
, 1, TRUE
);
295 void action_maximize_vert(union ActionData
*data
)
298 client_maximize(data
->client
.c
, TRUE
, 2, TRUE
);
301 void action_unmaximize_vert(union ActionData
*data
)
304 client_maximize(data
->client
.c
, FALSE
, 2, TRUE
);
307 void action_toggle_maximize_vert(union ActionData
*data
)
310 client_maximize(data
->client
.c
, !data
->client
.c
->max_vert
, 2, TRUE
);
313 void action_send_to_desktop(union ActionData
*data
)
316 if (data
->sendto
.desktop
< screen_num_desktops
||
317 data
->sendto
.desktop
== DESKTOP_ALL
)
318 client_set_desktop(data
->sendto
.c
, data
->sendto
.desktop
);
321 void action_send_to_next_desktop(union ActionData
*data
)
325 if (!data
->sendto
.c
) return;
327 d
= screen_desktop
+ 1;
328 if (d
>= screen_num_desktops
) {
329 if (!data
->sendtonextprev
.wrap
) return;
332 client_set_desktop(data
->sendtonextprev
.c
, d
);
333 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
336 void action_send_to_previous_desktop(union ActionData
*data
)
340 if (!data
->sendto
.c
) return;
342 d
= screen_desktop
- 1;
343 if (d
>= screen_num_desktops
) {
344 if (!data
->sendtonextprev
.wrap
) return;
345 d
= screen_num_desktops
- 1;
347 client_set_desktop(data
->sendtonextprev
.c
, d
);
348 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
351 void action_desktop(union ActionData
*data
)
353 if (data
->desktop
.desk
< screen_num_desktops
||
354 data
->desktop
.desk
== DESKTOP_ALL
)
355 screen_set_desktop(data
->desktop
.desk
);
358 void action_next_desktop(union ActionData
*data
)
362 d
= screen_desktop
+ 1;
363 if (d
>= screen_num_desktops
) {
364 if (!data
->nextprevdesktop
.wrap
) return;
367 screen_set_desktop(d
);
370 void action_previous_desktop(union ActionData
*data
)
374 d
= screen_desktop
- 1;
375 if (d
>= screen_num_desktops
) {
376 if (!data
->nextprevdesktop
.wrap
) return;
377 d
= screen_num_desktops
- 1;
379 screen_set_desktop(d
);
382 static void cur_row_col(guint
*r
, guint
*c
)
384 switch (screen_desktop_layout
.orientation
) {
385 case Orientation_Horz
:
386 switch (screen_desktop_layout
.start_corner
) {
388 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
389 *c
= screen_desktop
% screen_desktop_layout
.columns
;
391 case Corner_BottomLeft
:
392 *r
= screen_desktop_layout
.rows
- 1 -
393 screen_desktop
/ screen_desktop_layout
.columns
;
394 *c
= screen_desktop
% screen_desktop_layout
.columns
;
397 case Corner_TopRight
:
398 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
399 *c
= screen_desktop_layout
.columns
- 1 -
400 screen_desktop
% screen_desktop_layout
.columns
;
402 case Corner_BottomRight
:
403 *r
= screen_desktop_layout
.rows
- 1 -
404 screen_desktop
/ screen_desktop_layout
.columns
;
405 *c
= screen_desktop_layout
.columns
- 1 -
406 screen_desktop
% screen_desktop_layout
.columns
;
410 case Orientation_Vert
:
411 switch (screen_desktop_layout
.start_corner
) {
413 *r
= screen_desktop
% screen_desktop_layout
.rows
;
414 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
416 case Corner_BottomLeft
:
417 *r
= screen_desktop_layout
.rows
- 1 -
418 screen_desktop
% screen_desktop_layout
.rows
;
419 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
422 case Corner_TopRight
:
423 *r
= screen_desktop
% screen_desktop_layout
.rows
;
424 *c
= screen_desktop_layout
.columns
- 1 -
425 screen_desktop
/ screen_desktop_layout
.rows
;
427 case Corner_BottomRight
:
428 *r
= screen_desktop_layout
.rows
- 1 -
429 screen_desktop
% screen_desktop_layout
.rows
;
430 *c
= screen_desktop_layout
.columns
- 1 -
431 screen_desktop
/ screen_desktop_layout
.rows
;
439 static guint
translate_row_col(guint r
, guint c
)
441 switch (screen_desktop_layout
.orientation
) {
442 case Orientation_Horz
:
443 switch (screen_desktop_layout
.start_corner
) {
445 return r
* screen_desktop_layout
.columns
+ c
;
446 case Corner_BottomLeft
:
447 return (screen_desktop_layout
.rows
- 1 - r
) *
448 screen_desktop_layout
.columns
+ c
;
449 case Corner_TopRight
:
450 return r
* screen_desktop_layout
.columns
+
451 (screen_desktop_layout
.columns
- 1 - c
);
452 case Corner_BottomRight
:
453 return (screen_desktop_layout
.rows
- 1 - r
) *
454 screen_desktop_layout
.columns
+
455 (screen_desktop_layout
.columns
- 1 - c
);
457 case Orientation_Vert
:
458 switch (screen_desktop_layout
.start_corner
) {
460 return c
* screen_desktop_layout
.rows
+ r
;
461 case Corner_BottomLeft
:
462 return c
* screen_desktop_layout
.rows
+
463 (screen_desktop_layout
.rows
- 1 - r
);
464 case Corner_TopRight
:
465 return (screen_desktop_layout
.columns
- 1 - c
) *
466 screen_desktop_layout
.rows
+ r
;
467 case Corner_BottomRight
:
468 return (screen_desktop_layout
.columns
- 1 - c
) *
469 screen_desktop_layout
.rows
+
470 (screen_desktop_layout
.rows
- 1 - r
);
473 g_assert_not_reached();
477 void action_next_desktop_column(union ActionData
*data
)
483 d
= translate_row_col(r
, c
);
484 if (d
>= screen_num_desktops
) {
485 if (!data
->nextprevdesktop
.wrap
) return;
488 if (d
>= screen_num_desktops
)
490 d
= translate_row_col(r
, c
);
491 if (d
< screen_num_desktops
)
492 screen_set_desktop(d
);
495 void action_previous_desktop_column(union ActionData
*data
)
501 d
= translate_row_col(r
, c
);
502 if (d
>= screen_num_desktops
) {
503 if (!data
->nextprevdesktop
.wrap
) return;
504 c
= screen_desktop_layout
.columns
- 1;
506 if (d
>= screen_num_desktops
)
508 d
= translate_row_col(r
, c
);
509 if (d
< screen_num_desktops
)
510 screen_set_desktop(d
);
513 void action_next_desktop_row(union ActionData
*data
)
519 d
= translate_row_col(r
, c
);
520 if (d
>= screen_num_desktops
) {
521 if (!data
->nextprevdesktop
.wrap
) return;
524 if (d
>= screen_num_desktops
)
526 d
= translate_row_col(r
, c
);
527 if (d
< screen_num_desktops
)
528 screen_set_desktop(d
);
531 void action_previous_desktop_row(union ActionData
*data
)
537 d
= translate_row_col(r
, c
);
538 if (d
>= screen_num_desktops
) {
539 if (!data
->nextprevdesktop
.wrap
) return;
540 c
= screen_desktop_layout
.rows
- 1;
542 if (d
>= screen_num_desktops
)
544 d
= translate_row_col(r
, c
);
545 if (d
< screen_num_desktops
)
546 screen_set_desktop(d
);
549 void action_toggle_decorations(union ActionData
*data
)
551 Client
*c
= data
->client
.c
;
552 c
->disabled_decorations
= c
->disabled_decorations
? 0 : ~0;
553 client_setup_decor_and_functions(c
);
556 void action_move(union ActionData
*data
)
558 Client
*c
= data
->move
.c
;
559 int x
= data
->move
.x
;
560 int y
= data
->move
.y
;
562 if (!c
|| !client_normal(c
)) return;
564 dispatch_move(c
, &x
, &y
);
566 frame_frame_gravity(c
->frame
, &x
, &y
); /* get where the client should be */
567 client_configure(c
, Corner_TopLeft
, x
, y
, c
->area
.width
, c
->area
.height
,
568 TRUE
, data
->move
.final
);
571 void action_resize(union ActionData
*data
)
573 Client
*c
= data
->resize
.c
;
574 int w
= data
->resize
.x
- c
->frame
->size
.left
- c
->frame
->size
.right
;
575 int h
= data
->resize
.y
- c
->frame
->size
.top
- c
->frame
->size
.bottom
;
577 if (!c
|| !client_normal(c
)) return;
579 /* XXX window snapping/struts */
581 client_configure(c
, data
->resize
.corner
, c
->area
.x
, c
->area
.y
, w
, h
,
582 TRUE
, data
->resize
.final
);
585 void action_restart(union ActionData
*data
)
587 ob_restart_path
= data
->execute
.path
;
588 ob_shutdown
= ob_restart
= TRUE
;
591 void action_exit(union ActionData
*data
)