add the growtoedge action
[mikachu/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 } Options;
11
12 static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
13 static void     free_func(gpointer options);
14 static gboolean run_func(ObActionsData *data, gpointer options);
15
16 void action_growtoedge_startup()
17 {
18     actions_register("GrowToEdge",
19                      setup_func,
20                      free_func,
21                      run_func,
22                      NULL, NULL);
23 }
24
25 static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
26 {
27     xmlNodePtr n;
28     Options *o;
29
30     o = g_new0(Options, 1);
31     o->dir = OB_DIRECTION_NORTH;
32
33     if ((n = parse_find_node("direction", node))) {
34         gchar *s = parse_string(doc, n);
35         if (!g_ascii_strcasecmp(s, "north") ||
36             !g_ascii_strcasecmp(s, "up"))
37             o->dir = OB_DIRECTION_NORTH;
38         else if (!g_ascii_strcasecmp(s, "south") ||
39                  !g_ascii_strcasecmp(s, "down"))
40             o->dir = OB_DIRECTION_SOUTH;
41         else if (!g_ascii_strcasecmp(s, "west") ||
42                  !g_ascii_strcasecmp(s, "left"))
43             o->dir = OB_DIRECTION_WEST;
44         else if (!g_ascii_strcasecmp(s, "east") ||
45                  !g_ascii_strcasecmp(s, "right"))
46             o->dir = OB_DIRECTION_EAST;
47         g_free(s);
48     }
49
50     return o;
51 }
52
53 static void free_func(gpointer options)
54 {
55     Options *o = options;
56
57     g_free(o);
58 }
59
60 /* Always return FALSE because its not interactive */
61 static gboolean run_func(ObActionsData *data, gpointer options)
62 {
63     Options *o = options;
64
65     if (data->client) {
66         gint x, y, width, height, dest;
67         ObClient *c = data->client;
68         Rect *a;
69
70         a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area);
71         x = c->frame->area.x;
72         y = c->frame->area.y;
73         /* get the unshaded frame's dimensions..if it is shaded */
74         width = c->area.width + c->frame->size.left + c->frame->size.right;
75         height = c->area.height + c->frame->size.top + c->frame->size.bottom;
76
77         switch(o->dir) {
78         case OB_DIRECTION_NORTH:
79             if (c->shaded) break; /* don't allow vertical resize if shaded */
80
81             dest = client_directional_edge_search(c, o->dir, FALSE);
82             if (a->y == y)
83                 height = height / 2;
84             else {
85                 height = c->frame->area.y + height - dest;
86                 y = dest;
87             }
88             break;
89         case OB_DIRECTION_WEST:
90             dest = client_directional_edge_search(c, o->dir, FALSE);
91             if (a->x == x)
92                 width = width / 2;
93             else {
94                 width = c->frame->area.x + width - dest;
95                 x = dest;
96             }
97             break;
98         case OB_DIRECTION_SOUTH:
99             if (c->shaded) break; /* don't allow vertical resize if shaded */
100
101             dest = client_directional_edge_search(c, o->dir, FALSE);
102             if (a->y + a->height == y + c->frame->area.height) {
103                 height = c->frame->area.height / 2;
104                 y = a->y + a->height - height;
105             } else
106                 height = dest - c->frame->area.y;
107             y += (height - c->frame->area.height) % c->size_inc.height;
108             height -= (height - c->frame->area.height) % c->size_inc.height;
109             break;
110         case OB_DIRECTION_EAST:
111             dest = client_directional_edge_search(c, o->dir, FALSE);
112             if (a->x + a->width == x + c->frame->area.width) {
113                 width = c->frame->area.width / 2;
114                 x = a->x + a->width - width;
115             } else
116                 width = dest - c->frame->area.x;
117             x += (width - c->frame->area.width) % c->size_inc.width;
118             width -= (width - c->frame->area.width) % c->size_inc.width;
119             break;
120         default:
121             g_assert_not_reached();
122         }
123
124         width -= c->frame->size.left + c->frame->size.right;
125         height -= c->frame->size.top + c->frame->size.bottom;
126         frame_frame_gravity(c->frame, &x, &y);
127
128         actions_client_move(data, FALSE);
129         client_move_resize(c, x, y, width, height);
130         actions_client_move(data, TRUE);
131
132         g_free(a);
133     }
134
135     return FALSE;
136 }