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