3 #include "moveresize.h"
15 typedef struct ActionString {
17 void (*func)(union ActionData *);
18 void (*setup)(Action *);
21 Action *action_new(void (*func)(union ActionData *data))
23 Action *a = g_new0(Action, 1);
29 void action_free(Action *a)
31 if (a == NULL) return;
33 /* deal with pointers */
34 if (a->func == action_execute || a->func == action_restart)
35 g_free(a->data.execute.path);
36 else if (a->func == action_showmenu)
37 g_free(a->data.showmenu.name);
42 void setup_action_directional_focus_north(Action *a)
44 a->data.diraction.direction = Direction_North;
47 void setup_action_directional_focus_east(Action *a)
49 a->data.diraction.direction = Direction_East;
52 void setup_action_directional_focus_south(Action *a)
54 a->data.diraction.direction = Direction_South;
57 void setup_action_directional_focus_west(Action *a)
59 a->data.diraction.direction = Direction_West;
62 void setup_action_directional_focus_northeast(Action *a)
64 a->data.diraction.direction = Direction_NorthEast;
67 void setup_action_directional_focus_southeast(Action *a)
69 a->data.diraction.direction = Direction_SouthEast;
72 void setup_action_directional_focus_southwest(Action *a)
74 a->data.diraction.direction = Direction_SouthWest;
77 void setup_action_directional_focus_northwest(Action *a)
79 a->data.diraction.direction = Direction_NorthWest;
82 void setup_action_send_to_desktop(Action *a)
84 a->data.sendto.follow = TRUE;
87 void setup_action_send_to_np_desktop(Action *a)
89 a->data.sendtonextprev.wrap = FALSE;
90 a->data.sendtonextprev.follow = TRUE;
93 void setup_action_send_to_np_desktop_wrap(Action *a)
95 a->data.sendtonextprev.wrap = TRUE;
96 a->data.sendtonextprev.follow = TRUE;
99 void setup_action_np_desktop(Action *a)
101 a->data.nextprevdesktop.wrap = FALSE;
104 void setup_action_np_desktop_wrap(Action *a)
106 a->data.nextprevdesktop.wrap = TRUE;
109 void setup_action_move_keyboard(Action *a)
111 a->data.moveresize.corner = prop_atoms.net_wm_moveresize_move_keyboard;
114 void setup_action_move(Action *a)
116 a->data.moveresize.corner = prop_atoms.net_wm_moveresize_move;
119 void setup_action_resize(Action *a)
121 a->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_topleft;
124 void setup_action_resize_keyboard(Action *a)
126 a->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_keyboard;
129 void setup_action_cycle_windows_linear_next(Action *a)
131 a->data.cycle.linear = TRUE;
132 a->data.cycle.forward = TRUE;
135 void setup_action_cycle_windows_linear_previous(Action *a)
137 a->data.cycle.linear = TRUE;
138 a->data.cycle.forward = FALSE;
141 void setup_action_cycle_windows_next(Action *a)
143 a->data.cycle.linear = FALSE;
144 a->data.cycle.forward = TRUE;
147 void setup_action_cycle_windows_previous(Action *a)
149 a->data.cycle.linear = FALSE;
150 a->data.cycle.forward = FALSE;
153 void setup_action_movetoedge_north(Action *a)
155 a->data.diraction.direction = Direction_North;
158 void setup_action_movetoedge_south(Action *a)
160 a->data.diraction.direction = Direction_South;
163 void setup_action_movetoedge_east(Action *a)
165 a->data.diraction.direction = Direction_East;
168 void setup_action_movetoedge_west(Action *a)
170 a->data.diraction.direction = Direction_West;
173 void setup_action_top_layer(Action *a)
175 a->data.layer.layer = 1;
178 void setup_action_normal_layer(Action *a)
180 a->data.layer.layer = 0;
183 void setup_action_bottom_layer(Action *a)
185 a->data.layer.layer = -1;
188 ActionString actionstrings[] =
196 "directionalfocusnorth",
197 action_directional_focus,
198 setup_action_directional_focus_north
201 "directionalfocuseast",
202 action_directional_focus,
203 setup_action_directional_focus_east
206 "directionalfocussouth",
207 action_directional_focus,
208 setup_action_directional_focus_south
211 "directionalfocuswest",
212 action_directional_focus,
213 setup_action_directional_focus_west
216 "directionalfocusnortheast",
217 action_directional_focus,
218 setup_action_directional_focus_northeast
221 "directionalfocussoutheast",
222 action_directional_focus,
223 setup_action_directional_focus_southeast
226 "directionalfocussouthwest",
227 action_directional_focus,
228 setup_action_directional_focus_southwest
231 "directionalfocusnorthwest",
232 action_directional_focus,
233 setup_action_directional_focus_northwest
302 action_toggle_omnipresent,
307 action_move_relative_horz,
312 action_move_relative_vert,
316 "resizerelativehorz",
317 action_resize_relative_horz,
321 "resizerelativevert",
322 action_resize_relative_vert,
327 action_maximize_full,
332 action_unmaximize_full,
336 "togglemaximizefull",
337 action_toggle_maximize_full,
342 action_maximize_horz,
347 action_unmaximize_horz,
351 "togglemaximizehorz",
352 action_toggle_maximize_horz,
357 action_maximize_vert,
362 action_unmaximize_vert,
366 "togglemaximizevert",
367 action_toggle_maximize_vert,
372 action_send_to_desktop,
373 setup_action_send_to_desktop
377 action_send_to_next_desktop,
378 setup_action_send_to_np_desktop
381 "sendtonextdesktopwrap",
382 action_send_to_next_desktop,
383 setup_action_send_to_np_desktop_wrap
386 "sendtopreviousdesktop",
387 action_send_to_previous_desktop,
388 setup_action_send_to_np_desktop
391 "sendtopreviousdesktopwrap",
392 action_send_to_previous_desktop,
393 setup_action_send_to_np_desktop_wrap
403 setup_action_np_desktop
408 setup_action_np_desktop_wrap
412 action_previous_desktop,
413 setup_action_np_desktop
416 "previousdesktopwrap",
417 action_previous_desktop,
418 setup_action_np_desktop_wrap
422 action_next_desktop_column,
423 setup_action_np_desktop
426 "nextdesktopcolumnwrap",
427 action_next_desktop_column,
428 setup_action_np_desktop_wrap
431 "previousdesktopcolumn",
432 action_previous_desktop_column,
433 setup_action_np_desktop
436 "previousdesktopcolumnwrap",
437 action_previous_desktop_column,
438 setup_action_np_desktop_wrap
442 action_next_desktop_row,
443 setup_action_np_desktop
446 "nextdesktoprowwrap",
447 action_next_desktop_row,
448 setup_action_np_desktop_wrap
451 "previousdesktoprow",
452 action_previous_desktop_row,
453 setup_action_np_desktop
456 "previousdesktoprowwrap",
457 action_previous_desktop_row,
458 setup_action_np_desktop_wrap
462 action_toggle_decorations,
468 setup_action_move_keyboard
483 setup_action_resize_keyboard
502 action_send_to_layer,
503 setup_action_top_layer
508 setup_action_top_layer
512 action_send_to_layer,
513 setup_action_normal_layer
517 action_send_to_layer,
518 setup_action_bottom_layer
521 "togglealwaysonbottom",
523 setup_action_bottom_layer
527 action_cycle_windows,
528 setup_action_cycle_windows_linear_next
531 "previouswindowlinear",
532 action_cycle_windows,
533 setup_action_cycle_windows_linear_previous
537 action_cycle_windows,
538 setup_action_cycle_windows_next
542 action_cycle_windows,
543 setup_action_cycle_windows_previous
548 setup_action_movetoedge_north
553 setup_action_movetoedge_south
558 setup_action_movetoedge_west
563 setup_action_movetoedge_east
572 Action *action_from_string(char *name)
577 for (i = 0; actionstrings[i].name; i++)
578 if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
579 a = action_new(actionstrings[i].func);
580 if (actionstrings[i].setup)
581 actionstrings[i].setup(a);
587 void action_execute(union ActionData *data)
590 if (data->execute.path)
591 if (!g_spawn_command_line_async(data->execute.path, &e)) {
592 g_warning("failed to execute '%s': %s",
593 data->execute.path, e->message);
597 void action_focus(union ActionData *data)
600 client_focus(data->client.c);
603 void action_unfocus (union ActionData *data)
606 client_unfocus(data->client.c);
609 void action_iconify(union ActionData *data)
612 client_iconify(data->client.c, TRUE, TRUE);
615 void action_focusraise(union ActionData *data)
617 if (data->client.c) {
618 client_focus(data->client.c);
619 stacking_raise(CLIENT_AS_WINDOW(data->client.c));
623 void action_raise(union ActionData *data)
626 stacking_raise(CLIENT_AS_WINDOW(data->client.c));
629 void action_unshaderaise(union ActionData *data)
631 if (data->client.c) {
632 if (data->client.c->shaded)
633 client_shade(data->client.c, FALSE);
635 stacking_raise(CLIENT_AS_WINDOW(data->client.c));
639 void action_shadelower(union ActionData *data)
641 if (data->client.c) {
642 if (data->client.c->shaded)
643 stacking_lower(CLIENT_AS_WINDOW(data->client.c));
645 client_shade(data->client.c, TRUE);
649 void action_lower(union ActionData *data)
652 stacking_lower(CLIENT_AS_WINDOW(data->client.c));
655 void action_close(union ActionData *data)
658 client_close(data->client.c);
661 void action_kill(union ActionData *data)
664 client_kill(data->client.c);
667 void action_shade(union ActionData *data)
670 client_shade(data->client.c, TRUE);
673 void action_unshade(union ActionData *data)
676 client_shade(data->client.c, FALSE);
679 void action_toggle_shade(union ActionData *data)
682 client_shade(data->client.c, !data->client.c->shaded);
685 void action_toggle_omnipresent(union ActionData *data)
688 client_set_desktop(data->client.c,
689 data->client.c->desktop == DESKTOP_ALL ?
690 screen_desktop : DESKTOP_ALL, FALSE);
693 void action_move_relative_horz(union ActionData *data)
695 Client *c = data->relative.c;
697 client_configure(c, Corner_TopLeft,
698 c->area.x + data->relative.delta, c->area.y,
699 c->area.width, c->area.height, TRUE, TRUE);
702 void action_move_relative_vert(union ActionData *data)
704 Client *c = data->relative.c;
706 client_configure(c, Corner_TopLeft,
707 c->area.x, c->area.y + data->relative.delta,
708 c->area.width, c->area.height, TRUE, TRUE);
711 void action_resize_relative_horz(union ActionData *data)
713 Client *c = data->relative.c;
715 client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
717 data->relative.delta * c->size_inc.width,
718 c->area.height, TRUE, TRUE);
721 void action_resize_relative_vert(union ActionData *data)
723 Client *c = data->relative.c;
725 client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
726 c->area.width, c->area.height +
727 data->relative.delta * c->size_inc.height,
731 void action_maximize_full(union ActionData *data)
734 client_maximize(data->client.c, TRUE, 0, TRUE);
737 void action_unmaximize_full(union ActionData *data)
740 client_maximize(data->client.c, FALSE, 0, TRUE);
743 void action_toggle_maximize_full(union ActionData *data)
746 client_maximize(data->client.c,
747 !(data->client.c->max_horz ||
748 data->client.c->max_vert),
752 void action_maximize_horz(union ActionData *data)
755 client_maximize(data->client.c, TRUE, 1, TRUE);
758 void action_unmaximize_horz(union ActionData *data)
761 client_maximize(data->client.c, FALSE, 1, TRUE);
764 void action_toggle_maximize_horz(union ActionData *data)
767 client_maximize(data->client.c, !data->client.c->max_horz, 1, TRUE);
770 void action_maximize_vert(union ActionData *data)
773 client_maximize(data->client.c, TRUE, 2, TRUE);
776 void action_unmaximize_vert(union ActionData *data)
779 client_maximize(data->client.c, FALSE, 2, TRUE);
782 void action_toggle_maximize_vert(union ActionData *data)
785 client_maximize(data->client.c, !data->client.c->max_vert, 2, TRUE);
788 void action_send_to_desktop(union ActionData *data)
790 if (data->sendto.c) {
791 if (data->sendto.desk < screen_num_desktops ||
792 data->sendto.desk == DESKTOP_ALL) {
793 client_set_desktop(data->desktop.c,
794 data->sendto.desk, data->sendto.follow);
795 if (data->sendto.follow) screen_set_desktop(data->sendto.desk);
800 void action_send_to_next_desktop(union ActionData *data)
804 if (!data->sendtonextprev.c) return;
806 d = screen_desktop + 1;
807 if (d >= screen_num_desktops) {
808 if (!data->sendtonextprev.wrap) return;
811 client_set_desktop(data->sendtonextprev.c, d, data->sendtonextprev.follow);
812 if (data->sendtonextprev.follow) screen_set_desktop(d);
815 void action_send_to_previous_desktop(union ActionData *data)
819 if (!data->sendtonextprev.c) return;
821 d = screen_desktop - 1;
822 if (d >= screen_num_desktops) {
823 if (!data->sendtonextprev.wrap) return;
824 d = screen_num_desktops - 1;
826 client_set_desktop(data->sendtonextprev.c, d, data->sendtonextprev.follow);
827 if (data->sendtonextprev.follow) screen_set_desktop(d);
830 void action_desktop(union ActionData *data)
832 if (data->desktop.desk < screen_num_desktops ||
833 data->desktop.desk == DESKTOP_ALL)
834 screen_set_desktop(data->desktop.desk);
837 void action_next_desktop(union ActionData *data)
841 d = screen_desktop + 1;
842 if (d >= screen_num_desktops) {
843 if (!data->nextprevdesktop.wrap) return;
846 screen_set_desktop(d);
849 void action_previous_desktop(union ActionData *data)
853 d = screen_desktop - 1;
854 if (d >= screen_num_desktops) {
855 if (!data->nextprevdesktop.wrap) return;
856 d = screen_num_desktops - 1;
858 screen_set_desktop(d);
861 static void cur_row_col(guint *r, guint *c)
863 switch (screen_desktop_layout.orientation) {
864 case Orientation_Horz:
865 switch (screen_desktop_layout.start_corner) {
867 *r = screen_desktop / screen_desktop_layout.columns;
868 *c = screen_desktop % screen_desktop_layout.columns;
870 case Corner_BottomLeft:
871 *r = screen_desktop_layout.rows - 1 -
872 screen_desktop / screen_desktop_layout.columns;
873 *c = screen_desktop % screen_desktop_layout.columns;
875 case Corner_TopRight:
876 *r = screen_desktop / screen_desktop_layout.columns;
877 *c = screen_desktop_layout.columns - 1 -
878 screen_desktop % screen_desktop_layout.columns;
880 case Corner_BottomRight:
881 *r = screen_desktop_layout.rows - 1 -
882 screen_desktop / screen_desktop_layout.columns;
883 *c = screen_desktop_layout.columns - 1 -
884 screen_desktop % screen_desktop_layout.columns;
888 case Orientation_Vert:
889 switch (screen_desktop_layout.start_corner) {
891 *r = screen_desktop % screen_desktop_layout.rows;
892 *c = screen_desktop / screen_desktop_layout.rows;
894 case Corner_BottomLeft:
895 *r = screen_desktop_layout.rows - 1 -
896 screen_desktop % screen_desktop_layout.rows;
897 *c = screen_desktop / screen_desktop_layout.rows;
899 case Corner_TopRight:
900 *r = screen_desktop % screen_desktop_layout.rows;
901 *c = screen_desktop_layout.columns - 1 -
902 screen_desktop / screen_desktop_layout.rows;
904 case Corner_BottomRight:
905 *r = screen_desktop_layout.rows - 1 -
906 screen_desktop % screen_desktop_layout.rows;
907 *c = screen_desktop_layout.columns - 1 -
908 screen_desktop / screen_desktop_layout.rows;
915 static guint translate_row_col(guint r, guint c)
917 switch (screen_desktop_layout.orientation) {
918 case Orientation_Horz:
919 switch (screen_desktop_layout.start_corner) {
921 return r % screen_desktop_layout.rows *
922 screen_desktop_layout.columns +
923 c % screen_desktop_layout.columns;
924 case Corner_BottomLeft:
925 return (screen_desktop_layout.rows - 1 -
926 r % screen_desktop_layout.rows) *
927 screen_desktop_layout.columns +
928 c % screen_desktop_layout.columns;
929 case Corner_TopRight:
930 return r % screen_desktop_layout.rows *
931 screen_desktop_layout.columns +
932 (screen_desktop_layout.columns - 1 -
933 c % screen_desktop_layout.columns);
934 case Corner_BottomRight:
935 return (screen_desktop_layout.rows - 1 -
936 r % screen_desktop_layout.rows) *
937 screen_desktop_layout.columns +
938 (screen_desktop_layout.columns - 1 -
939 c % screen_desktop_layout.columns);
941 case Orientation_Vert:
942 switch (screen_desktop_layout.start_corner) {
944 return c % screen_desktop_layout.columns *
945 screen_desktop_layout.rows +
946 r % screen_desktop_layout.rows;
947 case Corner_BottomLeft:
948 return c % screen_desktop_layout.columns *
949 screen_desktop_layout.rows +
950 (screen_desktop_layout.rows - 1 -
951 r % screen_desktop_layout.rows);
952 case Corner_TopRight:
953 return (screen_desktop_layout.columns - 1 -
954 c % screen_desktop_layout.columns) *
955 screen_desktop_layout.rows +
956 r % screen_desktop_layout.rows;
957 case Corner_BottomRight:
958 return (screen_desktop_layout.columns - 1 -
959 c % screen_desktop_layout.columns) *
960 screen_desktop_layout.rows +
961 (screen_desktop_layout.rows - 1 -
962 r % screen_desktop_layout.rows);
965 g_assert_not_reached();
969 void action_next_desktop_column(union ActionData *data)
975 if (c >= screen_desktop_layout.columns)
977 d = translate_row_col(r, c);
978 if (d >= screen_num_desktops) {
979 if (!data->nextprevdesktop.wrap) return;
982 d = translate_row_col(r, c);
983 if (d < screen_num_desktops)
984 screen_set_desktop(d);
987 void action_previous_desktop_column(union ActionData *data)
993 if (c >= screen_desktop_layout.columns)
994 c = screen_desktop_layout.columns - 1;
995 d = translate_row_col(r, c);
996 if (d >= screen_num_desktops) {
997 if (!data->nextprevdesktop.wrap) return;
1000 d = translate_row_col(r, c);
1001 if (d < screen_num_desktops)
1002 screen_set_desktop(d);
1005 void action_next_desktop_row(union ActionData *data)
1009 cur_row_col(&r, &c);
1011 if (r >= screen_desktop_layout.rows)
1013 d = translate_row_col(r, c);
1014 if (d >= screen_num_desktops) {
1015 if (!data->nextprevdesktop.wrap) return;
1018 d = translate_row_col(r, c);
1019 if (d < screen_num_desktops)
1020 screen_set_desktop(d);
1023 void action_previous_desktop_row(union ActionData *data)
1027 cur_row_col(&r, &c);
1029 if (r >= screen_desktop_layout.rows)
1030 r = screen_desktop_layout.rows - 1;
1031 d = translate_row_col(r, c);
1032 if (d >= screen_num_desktops) {
1033 if (!data->nextprevdesktop.wrap) return;
1036 d = translate_row_col(r, c);
1037 if (d < screen_num_desktops)
1038 screen_set_desktop(d);
1041 void action_toggle_decorations(union ActionData *data)
1043 Client *c = data->client.c;;
1047 c->disabled_decorations = c->disabled_decorations ? 0 : ~0;
1048 client_setup_decor_and_functions(c);
1051 void action_moveresize(union ActionData *data)
1053 Client *c = data->moveresize.c;
1055 if (!c || !client_normal(c)) return;
1057 moveresize_start(c, data->moveresize.x, data->moveresize.y,
1058 data->moveresize.button, data->moveresize.corner);
1061 void action_restart(union ActionData *data)
1063 ob_restart_path = data->execute.path;
1064 ob_shutdown = ob_restart = TRUE;
1067 void action_exit(union ActionData *data)
1072 void action_showmenu(union ActionData *data)
1074 if (data->showmenu.name) {
1075 menu_show(data->showmenu.name, data->showmenu.x, data->showmenu.y,
1080 void action_cycle_windows(union ActionData *data)
1084 c = focus_cycle(data->cycle.forward, data->cycle.linear, data->cycle.final,
1085 data->cycle.cancel);
1088 void action_directional_focus(union ActionData *data)
1092 if (!data->diraction.c)
1094 if ((nf = client_find_directional(data->diraction.c,
1095 data->diraction.direction)))
1096 client_activate(nf);
1099 void action_movetoedge(union ActionData *data)
1102 Client *c = data->diraction.c;
1106 x = c->frame->area.x;
1107 y = c->frame->area.y;
1109 h = screen_area(c->desktop)->height;
1110 w = screen_area(c->desktop)->width;
1111 switch(data->diraction.direction) {
1112 case Direction_North:
1115 case Direction_West:
1118 case Direction_South:
1119 y = h - c->frame->area.height;
1121 case Direction_East:
1122 x = w - c->frame->area.width;
1125 frame_frame_gravity(c->frame, &x, &y);
1126 client_configure(c, Corner_TopLeft,
1127 x, y, c->area.width, c->area.height, TRUE, TRUE);
1131 void action_send_to_layer(union ActionData *data)
1134 client_set_layer(data->layer.c, data->layer.layer);
1137 void action_toggle_layer(union ActionData *data)
1139 Client *c = data->layer.c;
1142 if (data->layer.layer < 0)
1143 client_set_layer(c, c->below ? 0 : -1);
1144 else if (data->layer.layer > 0)
1145 client_set_layer(c, c->above ? 0 : 1);