Merge branch 'backport' into work
[mikachu/openbox.git] / openbox / actions / growtoedge.c
1 #include "openbox/actions.h"
2 #include "openbox/misc.h"
3 #include "openbox/client.h"
4 #include "openbox/frame.h"
5 #include "openbox/screen.h"
6 #include <glib.h>
7
8 typedef struct {
9     ObDirection dir;
10     gboolean shrink;
11 } Options;
12
13 static gpointer setup_func(xmlNodePtr node);
14 static gpointer setup_shrink_func(xmlNodePtr node);
15 static gboolean run_func(ObActionsData *data, gpointer options);
16 /* 3.4-compatibility */
17 static gpointer setup_north_func(xmlNodePtr node);
18 static gpointer setup_south_func(xmlNodePtr node);
19 static gpointer setup_east_func(xmlNodePtr node);
20 static gpointer setup_west_func(xmlNodePtr node);
21
22 void action_growtoedge_startup(void)
23 {
24     actions_register("GrowToEdge", setup_func,
25                      g_free, run_func);
26     actions_register("ShrinkToEdge", setup_shrink_func,
27                      g_free, run_func);
28     /* 3.4-compatibility */
29     actions_register("GrowToEdgeNorth", setup_north_func, g_free, run_func);
30     actions_register("GrowToEdgeSouth", setup_south_func, g_free, run_func);
31     actions_register("GrowToEdgeEast", setup_east_func, g_free, run_func);
32     actions_register("GrowToEdgeWest", setup_west_func, g_free, run_func);
33 }
34
35 static gpointer setup_func(xmlNodePtr node)
36 {
37     xmlNodePtr n;
38     Options *o;
39
40     o = g_new0(Options, 1);
41     o->dir = OB_DIRECTION_NORTH;
42     o->shrink = FALSE;
43
44     if ((n = obt_parse_find_node(node, "direction"))) {
45         gchar *s = obt_parse_node_string(n);
46         if (!g_ascii_strcasecmp(s, "north") ||
47             !g_ascii_strcasecmp(s, "up"))
48             o->dir = OB_DIRECTION_NORTH;
49         else if (!g_ascii_strcasecmp(s, "south") ||
50                  !g_ascii_strcasecmp(s, "down"))
51             o->dir = OB_DIRECTION_SOUTH;
52         else if (!g_ascii_strcasecmp(s, "west") ||
53                  !g_ascii_strcasecmp(s, "left"))
54             o->dir = OB_DIRECTION_WEST;
55         else if (!g_ascii_strcasecmp(s, "east") ||
56                  !g_ascii_strcasecmp(s, "right"))
57             o->dir = OB_DIRECTION_EAST;
58         g_free(s);
59     }
60
61     return o;
62 }
63
64 static gpointer setup_shrink_func(xmlNodePtr node)
65 {
66     Options *o;
67
68     o = setup_func(node);
69     o->shrink = TRUE;
70
71     return o;
72 }
73
74 static gboolean do_grow(ObActionsData *data, gint x, gint y, gint w, gint h)
75 {
76     gint realw, realh, lw, lh;
77
78     realw = w;
79     realh = h;
80     client_try_configure(data->client, &x, &y, &realw, &realh,
81                          &lw, &lh, TRUE);
82     /* if it's going to be resized smaller than it intended, don't
83        move the window over */
84     if (x != data->client->area.x) x += w - realw;
85     if (y != data->client->area.y) y += h - realh;
86
87     if (x != data->client->area.x || y != data->client->area.y ||
88         realw != data->client->area.width ||
89         realh != data->client->area.height)
90     {
91         actions_client_move(data, TRUE);
92         client_move_resize(data->client, x, y, realw, realh);
93         actions_client_move(data, FALSE);
94         return TRUE;
95     }
96     return FALSE;
97 }
98
99 /* Always return FALSE because its not interactive */
100 static gboolean run_func(ObActionsData *data, gpointer options)
101 {
102     Options *o = options;
103     gint x, y, w, h;
104     ObDirection opp;
105     gint half;
106
107     if (!data->client ||
108         /* don't allow vertical resize if shaded */
109         ((o->dir == OB_DIRECTION_NORTH || o->dir == OB_DIRECTION_SOUTH) &&
110          data->client->shaded))
111     {
112         return FALSE;
113     }
114
115     if (!o->shrink) {
116         /* try grow */
117         client_find_resize_directional(data->client, o->dir, TRUE,
118                                        &x, &y, &w, &h);
119         if (do_grow(data, x, y, w, h))
120             return FALSE;
121     }
122
123     /* we couldn't grow, so try shrink! */
124     opp = (o->dir == OB_DIRECTION_NORTH ? OB_DIRECTION_SOUTH :
125            (o->dir == OB_DIRECTION_SOUTH ? OB_DIRECTION_NORTH :
126             (o->dir == OB_DIRECTION_EAST ? OB_DIRECTION_WEST :
127              OB_DIRECTION_EAST)));
128     client_find_resize_directional(data->client, opp, FALSE,
129                                    &x, &y, &w, &h);
130     switch (opp) {
131     case OB_DIRECTION_NORTH:
132         half = data->client->area.y + data->client->area.height / 2;
133         if (y > half) {
134             h += y - half;
135             y = half;
136         }
137         break;
138     case OB_DIRECTION_SOUTH:
139         half = data->client->area.height / 2;
140         if (h < half)
141             h = half;
142         break;
143     case OB_DIRECTION_WEST:
144         half = data->client->area.x + data->client->area.width / 2;
145         if (x > half) {
146             w += x - half;
147             x = half;
148         }
149         break;
150     case OB_DIRECTION_EAST:
151         half = data->client->area.width / 2;
152         if (w < half)
153             w = half;
154         break;
155     default: g_assert_not_reached();
156     }
157     if (do_grow(data, x, y, w, h))
158         return FALSE;
159
160     return FALSE;
161 }
162
163 /* 3.4-compatibility */
164 static gpointer setup_north_func(xmlNodePtr node)
165 {
166     Options *o = g_new0(Options, 1);
167     o->shrink = FALSE;
168     o->dir = OB_DIRECTION_NORTH;
169     return o;
170 }
171
172 static gpointer setup_south_func(xmlNodePtr node)
173 {
174     Options *o = g_new0(Options, 1);
175     o->shrink = FALSE;
176     o->dir = OB_DIRECTION_SOUTH;
177     return o;
178 }
179
180 static gpointer setup_east_func(xmlNodePtr node)
181 {
182     Options *o = g_new0(Options, 1);
183     o->shrink = FALSE;
184     o->dir = OB_DIRECTION_EAST;
185     return o;
186 }
187
188 static gpointer setup_west_func(xmlNodePtr node)
189 {
190     Options *o = g_new0(Options, 1);
191     o->shrink = FALSE;
192     o->dir = OB_DIRECTION_WEST;
193     return o;
194 }