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