]> icculus.org git repositories - dana/openbox.git/blob - openbox/actions/growtoedge.c
Rename ObActions* to ObAction* and remove more 3.4-compat action stuff that was missed.
[dana/openbox.git] / openbox / actions / growtoedge.c
1 #include "openbox/action.h"
2 #include "openbox/action_value.h"
3 #include "openbox/misc.h"
4 #include "openbox/client.h"
5 #include "openbox/frame.h"
6 #include "openbox/screen.h"
7 #include <glib.h>
8
9 typedef struct {
10     ObDirection dir;
11     gboolean shrink;
12 } Options;
13
14 static gpointer setup_func(GHashTable *config);
15 static gpointer setup_shrink_func(GHashTable *config);
16 static void free_func(gpointer o);
17 static gboolean run_func(ObActionData *data, gpointer options);
18
19 void action_growtoedge_startup(void)
20 {
21     action_register("GrowToEdge", setup_func, free_func, run_func);
22     action_register("ShrinkToEdge", setup_shrink_func, free_func, run_func);
23 }
24
25 static gpointer setup_func(GHashTable *config)
26 {
27     ObActionValue *v;
28     Options *o;
29
30     o = g_slice_new0(Options);
31     o->dir = OB_DIRECTION_NORTH;
32     o->shrink = FALSE;
33
34     v = g_hash_table_lookup(config, "direction");
35     if (v && action_value_is_string(v)) {
36         const gchar *s = action_value_string(v);
37         if (!g_ascii_strcasecmp(s, "north") ||
38             !g_ascii_strcasecmp(s, "up"))
39             o->dir = OB_DIRECTION_NORTH;
40         else if (!g_ascii_strcasecmp(s, "south") ||
41                  !g_ascii_strcasecmp(s, "down"))
42             o->dir = OB_DIRECTION_SOUTH;
43         else if (!g_ascii_strcasecmp(s, "west") ||
44                  !g_ascii_strcasecmp(s, "left"))
45             o->dir = OB_DIRECTION_WEST;
46         else if (!g_ascii_strcasecmp(s, "east") ||
47                  !g_ascii_strcasecmp(s, "right"))
48             o->dir = OB_DIRECTION_EAST;
49     }
50
51     return o;
52 }
53
54 static gpointer setup_shrink_func(GHashTable *config)
55 {
56     Options *o;
57
58     o = setup_func(config);
59     o->shrink = TRUE;
60
61     return o;
62 }
63
64 static gboolean do_grow(ObActionData *data, gint x, gint y, gint w, gint h)
65 {
66     gint realw, realh, lw, lh;
67
68     realw = w;
69     realh = h;
70     client_try_configure(data->client, &x, &y, &realw, &realh,
71                          &lw, &lh, TRUE);
72     /* if it's going to be resized smaller than it intended, don't
73        move the window over */
74     if (x != data->client->area.x) x += w - realw;
75     if (y != data->client->area.y) y += h - realh;
76
77     if (x != data->client->area.x || y != data->client->area.y ||
78         realw != data->client->area.width ||
79         realh != data->client->area.height)
80     {
81         action_client_move(data, TRUE);
82         client_move_resize(data->client, x, y, realw, realh);
83         action_client_move(data, FALSE);
84         return TRUE;
85     }
86     return FALSE;
87 }
88
89 static void free_func(gpointer o)
90 {
91     g_slice_free(Options, o);
92 }
93
94 /* Always return FALSE because its not interactive */
95 static gboolean run_func(ObActionData *data, gpointer options)
96 {
97     Options *o = options;
98     gint x, y, w, h;
99     ObDirection opp;
100     gint half;
101
102     if (!data->client ||
103         /* don't allow vertical resize if shaded */
104         ((o->dir == OB_DIRECTION_NORTH || o->dir == OB_DIRECTION_SOUTH) &&
105          data->client->shaded))
106     {
107         return FALSE;
108     }
109
110     if (!o->shrink) {
111         /* try grow */
112         client_find_resize_directional(data->client, o->dir, TRUE,
113                                        &x, &y, &w, &h);
114         if (do_grow(data, x, y, w, h))
115             return FALSE;
116     }
117
118     /* we couldn't grow, so try shrink! */
119     opp = (o->dir == OB_DIRECTION_NORTH ? OB_DIRECTION_SOUTH :
120            (o->dir == OB_DIRECTION_SOUTH ? OB_DIRECTION_NORTH :
121             (o->dir == OB_DIRECTION_EAST ? OB_DIRECTION_WEST :
122              OB_DIRECTION_EAST)));
123     client_find_resize_directional(data->client, opp, FALSE,
124                                    &x, &y, &w, &h);
125     switch (opp) {
126     case OB_DIRECTION_NORTH:
127         half = data->client->area.y + data->client->area.height / 2;
128         if (y > half) {
129             h += y - half;
130             y = half;
131         }
132         break;
133     case OB_DIRECTION_SOUTH:
134         half = data->client->area.height / 2;
135         if (h < half)
136             h = half;
137         break;
138     case OB_DIRECTION_WEST:
139         half = data->client->area.x + data->client->area.width / 2;
140         if (x > half) {
141             w += x - half;
142             x = half;
143         }
144         break;
145     case OB_DIRECTION_EAST:
146         half = data->client->area.width / 2;
147         if (w < half)
148             w = half;
149         break;
150     default: g_assert_not_reached();
151     }
152     if (do_grow(data, x, y, w, h))
153         return FALSE;
154
155     return FALSE;
156 }