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