3 #include "moveresize.h"
15 Action
*action_new(void (*func
)(union ActionData
*data
))
17 Action
*a
= g_new0(Action
, 1);
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
);
30 else if (a
->func
== action_showmenu
)
31 g_free(a
->data
.showmenu
.name
);
36 Action
*action_from_string(char *name
)
39 if (!g_ascii_strcasecmp(name
, "execute")) {
40 a
= action_new(action_execute
);
41 } else if (!g_ascii_strcasecmp(name
, "focus")) {
42 a
= action_new(action_focus
);
43 } else if (!g_ascii_strcasecmp(name
, "unfocus")) {
44 a
= action_new(action_unfocus
);
45 } else if (!g_ascii_strcasecmp(name
, "iconify")) {
46 a
= action_new(action_iconify
);
47 } else if (!g_ascii_strcasecmp(name
, "raise")) {
48 a
= action_new(action_raise
);
49 } else if (!g_ascii_strcasecmp(name
, "lower")) {
50 a
= action_new(action_lower
);
51 } else if (!g_ascii_strcasecmp(name
, "focusraise")) {
52 a
= action_new(action_focusraise
);
53 } else if (!g_ascii_strcasecmp(name
, "close")) {
54 a
= action_new(action_close
);
55 } else if (!g_ascii_strcasecmp(name
, "kill")) {
56 a
= action_new(action_kill
);
57 } else if (!g_ascii_strcasecmp(name
, "shadelower")) {
58 a
= action_new(action_shadelower
);
59 } else if (!g_ascii_strcasecmp(name
, "unshaderaise")) {
60 a
= action_new(action_unshaderaise
);
61 } else if (!g_ascii_strcasecmp(name
, "shade")) {
62 a
= action_new(action_shade
);
63 } else if (!g_ascii_strcasecmp(name
, "unshade")) {
64 a
= action_new(action_unshade
);
65 } else if (!g_ascii_strcasecmp(name
, "toggleshade")) {
66 a
= action_new(action_toggle_shade
);
67 } else if (!g_ascii_strcasecmp(name
, "toggleomnipresent")) {
68 a
= action_new(action_toggle_omnipresent
);
69 } else if (!g_ascii_strcasecmp(name
, "moverelativehorz")) {
70 a
= action_new(action_move_relative_horz
);
71 } else if (!g_ascii_strcasecmp(name
, "moverelativevert")) {
72 a
= action_new(action_move_relative_vert
);
73 } else if (!g_ascii_strcasecmp(name
, "resizerelativehorz")) {
74 a
= action_new(action_resize_relative_horz
);
75 } else if (!g_ascii_strcasecmp(name
, "resizerelativevert")) {
76 a
= action_new(action_resize_relative_vert
);
77 } else if (!g_ascii_strcasecmp(name
, "maximizefull")) {
78 a
= action_new(action_maximize_full
);
79 } else if (!g_ascii_strcasecmp(name
, "unmaximizefull")) {
80 a
= action_new(action_unmaximize_full
);
81 } else if (!g_ascii_strcasecmp(name
, "togglemaximizefull")) {
82 a
= action_new(action_toggle_maximize_full
);
83 } else if (!g_ascii_strcasecmp(name
, "maximizehorz")) {
84 a
= action_new(action_maximize_horz
);
85 } else if (!g_ascii_strcasecmp(name
, "unmaximizehorz")) {
86 a
= action_new(action_unmaximize_horz
);
87 } else if (!g_ascii_strcasecmp(name
, "togglemaximizehorz")) {
88 a
= action_new(action_toggle_maximize_horz
);
89 } else if (!g_ascii_strcasecmp(name
, "maximizevert")) {
90 a
= action_new(action_maximize_vert
);
91 } else if (!g_ascii_strcasecmp(name
, "unmaximizevert")) {
92 a
= action_new(action_unmaximize_vert
);
93 } else if (!g_ascii_strcasecmp(name
, "togglemaximizevert")) {
94 a
= action_new(action_toggle_maximize_vert
);
95 } else if (!g_ascii_strcasecmp(name
, "sendtodesktop")) {
96 a
= action_new(action_send_to_desktop
);
97 a
->data
.sendto
.follow
= TRUE
;
98 } else if (!g_ascii_strcasecmp(name
, "sendtonextdesktop")) {
99 a
= action_new(action_send_to_next_desktop
);
100 a
->data
.sendtonextprev
.wrap
= FALSE
;
101 a
->data
.sendtonextprev
.follow
= TRUE
;
102 } else if (!g_ascii_strcasecmp(name
, "sendtonextdesktopwrap")) {
103 a
= action_new(action_send_to_next_desktop
);
104 a
->data
.sendtonextprev
.wrap
= TRUE
;
105 a
->data
.sendtonextprev
.follow
= TRUE
;
106 } else if (!g_ascii_strcasecmp(name
, "sendtopreviousdesktop")) {
107 a
= action_new(action_send_to_previous_desktop
);
108 a
->data
.sendtonextprev
.wrap
= FALSE
;
109 a
->data
.sendtonextprev
.follow
= TRUE
;
110 } else if (!g_ascii_strcasecmp(name
, "sendtopreviousdesktopwrap")) {
111 a
= action_new(action_send_to_previous_desktop
);
112 a
->data
.sendtonextprev
.wrap
= TRUE
;
113 a
->data
.sendtonextprev
.follow
= TRUE
;
114 } else if (!g_ascii_strcasecmp(name
, "desktop")) {
115 a
= action_new(action_desktop
);
116 } else if (!g_ascii_strcasecmp(name
, "nextdesktop")) {
117 a
= action_new(action_next_desktop
);
118 a
->data
.nextprevdesktop
.wrap
= FALSE
;
119 } else if (!g_ascii_strcasecmp(name
, "nextdesktopwrap")) {
120 a
= action_new(action_next_desktop
);
121 a
->data
.nextprevdesktop
.wrap
= TRUE
;
122 } else if (!g_ascii_strcasecmp(name
, "previousdesktop")) {
123 a
= action_new(action_previous_desktop
);
124 a
->data
.nextprevdesktop
.wrap
= FALSE
;
125 } else if (!g_ascii_strcasecmp(name
, "previousdesktopwrap")) {
126 a
= action_new(action_previous_desktop
);
127 a
->data
.nextprevdesktop
.wrap
= TRUE
;
128 } else if (!g_ascii_strcasecmp(name
, "nextdesktopcolumn")) {
129 a
= action_new(action_next_desktop_column
);
130 a
->data
.nextprevdesktop
.wrap
= FALSE
;
131 } else if (!g_ascii_strcasecmp(name
, "nextdesktopcolumnwrap")) {
132 a
= action_new(action_next_desktop_column
);
133 a
->data
.nextprevdesktop
.wrap
= TRUE
;
134 } else if (!g_ascii_strcasecmp(name
, "previousdesktopcolumn")) {
135 a
= action_new(action_previous_desktop_column
);
136 a
->data
.nextprevdesktop
.wrap
= FALSE
;
137 } else if (!g_ascii_strcasecmp(name
, "previousdesktopcolumnwrap")) {
138 a
= action_new(action_previous_desktop_column
);
139 a
->data
.nextprevdesktop
.wrap
= TRUE
;
140 } else if (!g_ascii_strcasecmp(name
, "nextdesktoprow")) {
141 a
= action_new(action_next_desktop_row
);
142 a
->data
.nextprevdesktop
.wrap
= FALSE
;
143 } else if (!g_ascii_strcasecmp(name
, "nextdesktoprowwrap")) {
144 a
= action_new(action_next_desktop_row
);
145 a
->data
.nextprevdesktop
.wrap
= TRUE
;
146 } else if (!g_ascii_strcasecmp(name
, "previousdesktoprow")) {
147 a
= action_new(action_previous_desktop_row
);
148 a
->data
.nextprevdesktop
.wrap
= FALSE
;
149 } else if (!g_ascii_strcasecmp(name
, "previousdesktoprowwrap")) {
150 a
= action_new(action_previous_desktop_row
);
151 a
->data
.nextprevdesktop
.wrap
= TRUE
;
152 } else if (!g_ascii_strcasecmp(name
, "toggledecorations")) {
153 a
= action_new(action_toggle_decorations
);
154 } else if (!g_ascii_strcasecmp(name
, "keyboardmove")) {
155 a
= action_new(action_moveresize
);
156 a
->data
.moveresize
.corner
= prop_atoms
.net_wm_moveresize_move_keyboard
;
157 } else if (!g_ascii_strcasecmp(name
, "move")) {
158 a
= action_new(action_moveresize
);
159 a
->data
.moveresize
.corner
= prop_atoms
.net_wm_moveresize_move
;
160 } else if (!g_ascii_strcasecmp(name
, "resize")) {
161 a
= action_new(action_moveresize
);
162 a
->data
.moveresize
.corner
= prop_atoms
.net_wm_moveresize_size_topleft
;
163 } else if (!g_ascii_strcasecmp(name
, "keyboardresize")) {
164 a
= action_new(action_moveresize
);
165 a
->data
.moveresize
.corner
= prop_atoms
.net_wm_moveresize_size_keyboard
;
166 } else if (!g_ascii_strcasecmp(name
, "restart")) {
167 a
= action_new(action_restart
);
168 } else if (!g_ascii_strcasecmp(name
, "exit")) {
169 a
= action_new(action_exit
);
170 } else if (!g_ascii_strcasecmp(name
, "showmenu")) {
171 a
= action_new(action_showmenu
);
172 } else if (!g_ascii_strcasecmp(name
, "nextwindowlinear")) {
173 a
= action_new(action_cycle_windows
);
174 a
->data
.cycle
.linear
= TRUE
;
175 a
->data
.cycle
.forward
= TRUE
;
176 } else if (!g_ascii_strcasecmp(name
, "previouswindowlinear")) {
177 a
= action_new(action_cycle_windows
);
178 a
->data
.cycle
.linear
= TRUE
;
179 a
->data
.cycle
.forward
= FALSE
;
180 } else if (!g_ascii_strcasecmp(name
, "nextwindow")) {
181 a
= action_new(action_cycle_windows
);
182 a
->data
.cycle
.linear
= FALSE
;
183 a
->data
.cycle
.forward
= TRUE
;
184 } else if (!g_ascii_strcasecmp(name
, "previouswindow")) {
185 a
= action_new(action_cycle_windows
);
186 a
->data
.cycle
.linear
= FALSE
;
187 a
->data
.cycle
.forward
= FALSE
;
193 void action_execute(union ActionData
*data
)
196 if (data
->execute
.path
)
197 if (!g_spawn_command_line_async(data
->execute
.path
, &e
)) {
198 g_warning("failed to execute '%s': %s",
199 data
->execute
.path
, e
->message
);
203 void action_focus(union ActionData
*data
)
206 client_focus(data
->client
.c
);
209 void action_unfocus (union ActionData
*data
)
212 client_unfocus(data
->client
.c
);
215 void action_iconify(union ActionData
*data
)
218 client_iconify(data
->client
.c
, TRUE
, TRUE
);
221 void action_focusraise(union ActionData
*data
)
223 if (data
->client
.c
) {
224 client_focus(data
->client
.c
);
225 stacking_raise(CLIENT_AS_WINDOW(data
->client
.c
));
229 void action_raise(union ActionData
*data
)
232 stacking_raise(CLIENT_AS_WINDOW(data
->client
.c
));
235 void action_unshaderaise(union ActionData
*data
)
237 if (data
->client
.c
) {
238 if (data
->client
.c
->shaded
)
239 client_shade(data
->client
.c
, FALSE
);
241 stacking_raise(CLIENT_AS_WINDOW(data
->client
.c
));
245 void action_shadelower(union ActionData
*data
)
247 if (data
->client
.c
) {
248 if (data
->client
.c
->shaded
)
249 stacking_lower(CLIENT_AS_WINDOW(data
->client
.c
));
251 client_shade(data
->client
.c
, TRUE
);
255 void action_lower(union ActionData
*data
)
258 stacking_lower(CLIENT_AS_WINDOW(data
->client
.c
));
261 void action_close(union ActionData
*data
)
264 client_close(data
->client
.c
);
267 void action_kill(union ActionData
*data
)
270 client_kill(data
->client
.c
);
273 void action_shade(union ActionData
*data
)
276 client_shade(data
->client
.c
, TRUE
);
279 void action_unshade(union ActionData
*data
)
282 client_shade(data
->client
.c
, FALSE
);
285 void action_toggle_shade(union ActionData
*data
)
288 client_shade(data
->client
.c
, !data
->client
.c
->shaded
);
291 void action_toggle_omnipresent(union ActionData
*data
)
294 client_set_desktop(data
->client
.c
,
295 data
->client
.c
->desktop
== DESKTOP_ALL
?
296 screen_desktop
: DESKTOP_ALL
, FALSE
);
299 void action_move_relative_horz(union ActionData
*data
)
301 Client
*c
= data
->relative
.c
;
303 client_configure(c
, Corner_TopLeft
,
304 c
->area
.x
+ data
->relative
.delta
, c
->area
.y
,
305 c
->area
.width
, c
->area
.height
, TRUE
, TRUE
);
308 void action_move_relative_vert(union ActionData
*data
)
310 Client
*c
= data
->relative
.c
;
312 client_configure(c
, Corner_TopLeft
,
313 c
->area
.x
, c
->area
.y
+ data
->relative
.delta
,
314 c
->area
.width
, c
->area
.height
, TRUE
, TRUE
);
317 void action_resize_relative_horz(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
+ data
->relative
.delta
,
323 c
->area
.height
, TRUE
, TRUE
);
326 void action_resize_relative_vert(union ActionData
*data
)
328 Client
*c
= data
->relative
.c
;
330 client_configure(c
, Corner_TopLeft
, c
->area
.x
, c
->area
.y
,
331 c
->area
.width
, c
->area
.height
+ data
->relative
.delta
,
335 void action_maximize_full(union ActionData
*data
)
338 client_maximize(data
->client
.c
, TRUE
, 0, TRUE
);
341 void action_unmaximize_full(union ActionData
*data
)
344 client_maximize(data
->client
.c
, FALSE
, 0, TRUE
);
347 void action_toggle_maximize_full(union ActionData
*data
)
350 client_maximize(data
->client
.c
,
351 !(data
->client
.c
->max_horz
||
352 data
->client
.c
->max_vert
),
356 void action_maximize_horz(union ActionData
*data
)
359 client_maximize(data
->client
.c
, TRUE
, 1, TRUE
);
362 void action_unmaximize_horz(union ActionData
*data
)
365 client_maximize(data
->client
.c
, FALSE
, 1, TRUE
);
368 void action_toggle_maximize_horz(union ActionData
*data
)
371 client_maximize(data
->client
.c
, !data
->client
.c
->max_horz
, 1, TRUE
);
374 void action_maximize_vert(union ActionData
*data
)
377 client_maximize(data
->client
.c
, TRUE
, 2, TRUE
);
380 void action_unmaximize_vert(union ActionData
*data
)
383 client_maximize(data
->client
.c
, FALSE
, 2, TRUE
);
386 void action_toggle_maximize_vert(union ActionData
*data
)
389 client_maximize(data
->client
.c
, !data
->client
.c
->max_vert
, 2, TRUE
);
392 void action_send_to_desktop(union ActionData
*data
)
394 if (data
->sendto
.c
) {
395 if (data
->sendto
.desk
< screen_num_desktops
||
396 data
->sendto
.desk
== DESKTOP_ALL
) {
397 client_set_desktop(data
->desktop
.c
,
398 data
->sendto
.desk
, data
->sendto
.follow
);
399 if (data
->sendto
.follow
) screen_set_desktop(data
->sendto
.desk
);
404 void action_send_to_next_desktop(union ActionData
*data
)
408 if (!data
->sendtonextprev
.c
) return;
410 d
= screen_desktop
+ 1;
411 if (d
>= screen_num_desktops
) {
412 if (!data
->sendtonextprev
.wrap
) return;
415 client_set_desktop(data
->sendtonextprev
.c
, d
, data
->sendtonextprev
.follow
);
416 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
419 void action_send_to_previous_desktop(union ActionData
*data
)
423 if (!data
->sendtonextprev
.c
) return;
425 d
= screen_desktop
- 1;
426 if (d
>= screen_num_desktops
) {
427 if (!data
->sendtonextprev
.wrap
) return;
428 d
= screen_num_desktops
- 1;
430 client_set_desktop(data
->sendtonextprev
.c
, d
, data
->sendtonextprev
.follow
);
431 if (data
->sendtonextprev
.follow
) screen_set_desktop(d
);
434 void action_desktop(union ActionData
*data
)
436 if (data
->desktop
.desk
< screen_num_desktops
||
437 data
->desktop
.desk
== DESKTOP_ALL
)
438 screen_set_desktop(data
->desktop
.desk
);
441 void action_next_desktop(union ActionData
*data
)
445 d
= screen_desktop
+ 1;
446 if (d
>= screen_num_desktops
) {
447 if (!data
->nextprevdesktop
.wrap
) return;
450 screen_set_desktop(d
);
453 void action_previous_desktop(union ActionData
*data
)
457 d
= screen_desktop
- 1;
458 if (d
>= screen_num_desktops
) {
459 if (!data
->nextprevdesktop
.wrap
) return;
460 d
= screen_num_desktops
- 1;
462 screen_set_desktop(d
);
465 static void cur_row_col(guint
*r
, guint
*c
)
467 switch (screen_desktop_layout
.orientation
) {
468 case Orientation_Horz
:
469 switch (screen_desktop_layout
.start_corner
) {
471 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
472 *c
= screen_desktop
% screen_desktop_layout
.columns
;
474 case Corner_BottomLeft
:
475 *r
= screen_desktop_layout
.rows
- 1 -
476 screen_desktop
/ screen_desktop_layout
.columns
;
477 *c
= screen_desktop
% screen_desktop_layout
.columns
;
479 case Corner_TopRight
:
480 *r
= screen_desktop
/ screen_desktop_layout
.columns
;
481 *c
= screen_desktop_layout
.columns
- 1 -
482 screen_desktop
% screen_desktop_layout
.columns
;
484 case Corner_BottomRight
:
485 *r
= screen_desktop_layout
.rows
- 1 -
486 screen_desktop
/ screen_desktop_layout
.columns
;
487 *c
= screen_desktop_layout
.columns
- 1 -
488 screen_desktop
% screen_desktop_layout
.columns
;
492 case Orientation_Vert
:
493 switch (screen_desktop_layout
.start_corner
) {
495 *r
= screen_desktop
% screen_desktop_layout
.rows
;
496 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
498 case Corner_BottomLeft
:
499 *r
= screen_desktop_layout
.rows
- 1 -
500 screen_desktop
% screen_desktop_layout
.rows
;
501 *c
= screen_desktop
/ screen_desktop_layout
.rows
;
503 case Corner_TopRight
:
504 *r
= screen_desktop
% screen_desktop_layout
.rows
;
505 *c
= screen_desktop_layout
.columns
- 1 -
506 screen_desktop
/ screen_desktop_layout
.rows
;
508 case Corner_BottomRight
:
509 *r
= screen_desktop_layout
.rows
- 1 -
510 screen_desktop
% screen_desktop_layout
.rows
;
511 *c
= screen_desktop_layout
.columns
- 1 -
512 screen_desktop
/ screen_desktop_layout
.rows
;
519 static guint
translate_row_col(guint r
, guint c
)
521 switch (screen_desktop_layout
.orientation
) {
522 case Orientation_Horz
:
523 switch (screen_desktop_layout
.start_corner
) {
525 return r
% screen_desktop_layout
.rows
*
526 screen_desktop_layout
.columns
+
527 c
% screen_desktop_layout
.columns
;
528 case Corner_BottomLeft
:
529 return (screen_desktop_layout
.rows
- 1 -
530 r
% screen_desktop_layout
.rows
) *
531 screen_desktop_layout
.columns
+
532 c
% screen_desktop_layout
.columns
;
533 case Corner_TopRight
:
534 return r
% screen_desktop_layout
.rows
*
535 screen_desktop_layout
.columns
+
536 (screen_desktop_layout
.columns
- 1 -
537 c
% screen_desktop_layout
.columns
);
538 case Corner_BottomRight
:
539 return (screen_desktop_layout
.rows
- 1 -
540 r
% screen_desktop_layout
.rows
) *
541 screen_desktop_layout
.columns
+
542 (screen_desktop_layout
.columns
- 1 -
543 c
% screen_desktop_layout
.columns
);
545 case Orientation_Vert
:
546 switch (screen_desktop_layout
.start_corner
) {
548 return c
% screen_desktop_layout
.columns
*
549 screen_desktop_layout
.rows
+
550 r
% screen_desktop_layout
.rows
;
551 case Corner_BottomLeft
:
552 return c
% screen_desktop_layout
.columns
*
553 screen_desktop_layout
.rows
+
554 (screen_desktop_layout
.rows
- 1 -
555 r
% screen_desktop_layout
.rows
);
556 case Corner_TopRight
:
557 return (screen_desktop_layout
.columns
- 1 -
558 c
% screen_desktop_layout
.columns
) *
559 screen_desktop_layout
.rows
+
560 r
% screen_desktop_layout
.rows
;
561 case Corner_BottomRight
:
562 return (screen_desktop_layout
.columns
- 1 -
563 c
% screen_desktop_layout
.columns
) *
564 screen_desktop_layout
.rows
+
565 (screen_desktop_layout
.rows
- 1 -
566 r
% screen_desktop_layout
.rows
);
569 g_assert_not_reached();
573 void action_next_desktop_column(union ActionData
*data
)
579 if (c
>= screen_desktop_layout
.columns
)
581 d
= translate_row_col(r
, c
);
582 if (d
>= screen_num_desktops
) {
583 if (!data
->nextprevdesktop
.wrap
) return;
586 d
= translate_row_col(r
, c
);
587 if (d
< screen_num_desktops
)
588 screen_set_desktop(d
);
591 void action_previous_desktop_column(union ActionData
*data
)
597 if (c
>= screen_desktop_layout
.columns
)
598 c
= screen_desktop_layout
.columns
- 1;
599 d
= translate_row_col(r
, c
);
600 if (d
>= screen_num_desktops
) {
601 if (!data
->nextprevdesktop
.wrap
) return;
604 d
= translate_row_col(r
, c
);
605 if (d
< screen_num_desktops
)
606 screen_set_desktop(d
);
609 void action_next_desktop_row(union ActionData
*data
)
615 if (r
>= screen_desktop_layout
.rows
)
617 d
= translate_row_col(r
, c
);
618 if (d
>= screen_num_desktops
) {
619 if (!data
->nextprevdesktop
.wrap
) return;
622 d
= translate_row_col(r
, c
);
623 if (d
< screen_num_desktops
)
624 screen_set_desktop(d
);
627 void action_previous_desktop_row(union ActionData
*data
)
633 if (r
>= screen_desktop_layout
.rows
)
634 r
= screen_desktop_layout
.rows
- 1;
635 d
= translate_row_col(r
, c
);
636 if (d
>= screen_num_desktops
) {
637 if (!data
->nextprevdesktop
.wrap
) return;
640 d
= translate_row_col(r
, c
);
641 if (d
< screen_num_desktops
)
642 screen_set_desktop(d
);
645 void action_toggle_decorations(union ActionData
*data
)
647 Client
*c
= data
->client
.c
;;
651 c
->disabled_decorations
= c
->disabled_decorations
? 0 : ~0;
652 client_setup_decor_and_functions(c
);
655 void action_moveresize(union ActionData
*data
)
657 Client
*c
= data
->moveresize
.c
;
659 if (!c
|| !client_normal(c
)) return;
661 moveresize_start(c
, data
->moveresize
.x
, data
->moveresize
.y
,
662 data
->moveresize
.button
, data
->moveresize
.corner
);
665 void action_restart(union ActionData
*data
)
667 ob_restart_path
= data
->execute
.path
;
668 ob_shutdown
= ob_restart
= TRUE
;
671 void action_exit(union ActionData
*data
)
676 void action_showmenu(union ActionData
*data
)
678 if (data
->showmenu
.name
) {
679 menu_show(data
->showmenu
.name
, data
->showmenu
.x
, data
->showmenu
.y
,
684 void action_cycle_windows(union ActionData
*data
)
688 c
= focus_cycle(data
->cycle
.forward
, data
->cycle
.linear
, data
->cycle
.final
,