Merge branch 'backport' into work
[mikachu/openbox.git] / openbox / actions / desktop.c
1 #include "openbox/actions.h"
2 #include "openbox/screen.h"
3 #include "openbox/client.h"
4 #include <glib.h>
5
6 typedef enum {
7     LAST,
8     RELATIVE,
9     ABSOLUTE
10 } SwitchType;
11
12 typedef struct {
13     SwitchType type;
14     union {
15         struct {
16             guint desktop;
17         } abs;
18
19         struct {
20             gboolean linear;
21             gboolean wrap;
22             ObDirection dir;
23         } rel;
24     };
25     gboolean send;
26     gboolean follow;
27 } Options;
28
29 static gpointer setup_go_func(xmlNodePtr node);
30 static gpointer setup_send_func(xmlNodePtr node);
31 static gboolean run_func(ObActionsData *data, gpointer options);
32
33 void action_desktop_startup(void)
34 {
35     actions_register("GoToDesktop", setup_go_func, g_free, run_func,
36                      NULL, NULL);
37     actions_register("SendToDesktop", setup_send_func, g_free, run_func,
38                      NULL, NULL);
39 }
40
41 static gpointer setup_go_func(xmlNodePtr node)
42 {
43     xmlNodePtr n;
44     Options *o;
45
46     o = g_new0(Options, 1);
47     /* don't go anywhere if theres no options given */
48     o->type = ABSOLUTE;
49     o->abs.desktop = screen_desktop;
50     /* wrap by default - it's handy! */
51     o->rel.wrap = TRUE;
52
53     if ((n = obt_parse_find_node(node, "to"))) {
54         gchar *s = obt_parse_node_string(n);
55         if (!g_ascii_strcasecmp(s, "last"))
56             o->type = LAST;
57         else if (!g_ascii_strcasecmp(s, "next")) {
58             o->type = RELATIVE;
59             o->rel.linear = TRUE;
60             o->rel.dir = OB_DIRECTION_EAST;
61         }
62         else if (!g_ascii_strcasecmp(s, "previous")) {
63             o->type = RELATIVE;
64             o->rel.linear = TRUE;
65             o->rel.dir = OB_DIRECTION_WEST;
66         }
67         else if (!g_ascii_strcasecmp(s, "north") ||
68                  !g_ascii_strcasecmp(s, "up")) {
69             o->type = RELATIVE;
70             o->rel.dir = OB_DIRECTION_NORTH;
71         }
72         else if (!g_ascii_strcasecmp(s, "south") ||
73                  !g_ascii_strcasecmp(s, "down")) {
74             o->type = RELATIVE;
75             o->rel.dir = OB_DIRECTION_SOUTH;
76         }
77         else if (!g_ascii_strcasecmp(s, "west") ||
78                  !g_ascii_strcasecmp(s, "left")) {
79             o->type = RELATIVE;
80             o->rel.dir = OB_DIRECTION_WEST;
81         }
82         else if (!g_ascii_strcasecmp(s, "east") ||
83                  !g_ascii_strcasecmp(s, "right")) {
84             o->type = RELATIVE;
85             o->rel.dir = OB_DIRECTION_EAST;
86         }
87         else {
88             o->type = ABSOLUTE;
89             o->abs.desktop = atoi(s) - 1;
90         }
91         g_free(s);
92     }
93
94     if ((n = obt_parse_find_node(node, "wrap")))
95         o->rel.wrap = obt_parse_node_bool(n);
96
97     return o;
98 }
99
100 static gpointer setup_send_func(xmlNodePtr node)
101 {
102     xmlNodePtr n;
103     Options *o;
104
105     o = setup_go_func(node);
106     o->send = TRUE;
107     o->follow = TRUE;
108
109     if ((n = obt_parse_find_node(node, "follow")))
110         o->follow = obt_parse_node_bool(n);
111
112     return o;
113 }
114
115 /* Always return FALSE because its not interactive */
116 static gboolean run_func(ObActionsData *data, gpointer options)
117 {
118     Options *o = options;
119     guint d;
120
121     switch (o->type) {
122     case LAST:
123         d = screen_last_desktop;
124         break;
125     case ABSOLUTE:
126         d = o->abs.desktop;
127         break;
128     case RELATIVE:
129         d = screen_find_desktop(screen_desktop,
130                                 o->rel.dir, o->rel.wrap, o->rel.linear);
131         break;
132     }
133
134     if (d < screen_num_desktops && d != screen_desktop) {
135         gboolean go = TRUE;
136
137         actions_client_move(data, TRUE);
138         if (o->send && data->client && client_normal(data->client)) {
139             client_set_desktop(data->client, d, o->follow, FALSE);
140             go = o->follow;
141         }
142
143         if (go) {
144             screen_set_desktop(d, TRUE);
145             if (data->client)
146                 client_bring_helper_windows(data->client);
147         }
148
149         actions_client_move(data, FALSE);
150     }
151     return FALSE;
152 }