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