Merge branch 'backport' into work
[dana/openbox.git] / openbox / actions / resize.c
1 #include "openbox/actions.h"
2 #include "openbox/moveresize.h"
3 #include "openbox/client.h"
4 #include "openbox/frame.h"
5 #include "obt/prop.h"
6
7 typedef struct {
8     gboolean corner_specified;
9     guint32 corner;
10 } Options;
11
12 static gpointer setup_func(xmlNodePtr node);
13 static gboolean run_func(ObActionsData *data, gpointer options);
14
15 static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch,
16                            gboolean shaded);
17
18 void action_resize_startup(void)
19 {
20     actions_register("Resize", setup_func, g_free, run_func);
21 }
22
23 static gpointer setup_func(xmlNodePtr node)
24 {
25     xmlNodePtr n;
26     Options *o;
27
28     o = g_new0(Options, 1);
29
30     if ((n = obt_xml_find_node(node, "edge"))) {
31         gchar *s = obt_xml_node_string(n);
32
33         o->corner_specified = TRUE;
34         if (!g_ascii_strcasecmp(s, "top"))
35             o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP);
36         else if (!g_ascii_strcasecmp(s, "bottom"))
37             o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM);
38         else if (!g_ascii_strcasecmp(s, "left"))
39             o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT);
40         else if (!g_ascii_strcasecmp(s, "right"))
41             o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT);
42         else if (!g_ascii_strcasecmp(s, "topleft"))
43             o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT);
44         else if (!g_ascii_strcasecmp(s, "topright"))
45             o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT);
46         else if (!g_ascii_strcasecmp(s, "bottomleft"))
47             o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT);
48         else if (!g_ascii_strcasecmp(s, "bottomright"))
49             o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT);
50         else
51             o->corner_specified = FALSE;
52
53         g_free(s);
54     }
55     return o;
56 }
57
58 /* Always return FALSE because its not interactive */
59 static gboolean run_func(ObActionsData *data, gpointer options)
60 {
61     Options *o = options;
62
63     if (data->client) {
64         ObClient *c = data->client;
65         guint32 corner;
66
67         if (!data->button)
68             corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD);
69         else if (o->corner_specified)
70             corner = o->corner; /* it was specified in the binding */
71         else
72             corner = pick_corner(data->x, data->y,
73                                  c->frame->area.x, c->frame->area.y,
74                                  /* use the client size because the frame
75                                     can be differently sized (shaded
76                                     windows) and we want this based on the
77                                     clients size */
78                                  c->area.width + c->frame->size.left +
79                                  c->frame->size.right,
80                                  c->area.height + c->frame->size.top +
81                                  c->frame->size.bottom, c->shaded);
82
83         moveresize_start(c, data->x, data->y, data->button, corner);
84     }
85
86     return FALSE;
87 }
88
89 static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch,
90                            gboolean shaded)
91 {
92     /* let's make x and y client relative instead of screen relative */
93     x = x - cx;
94     y = ch - (y - cy); /* y is inverted, 0 is at the bottom of the window */
95
96 #define X x*ch/cw
97 #define A -4*X + 7*ch/3
98 #define B  4*X -15*ch/9
99 #define C -X/4 + 2*ch/3
100 #define D  X/4 + 5*ch/12
101 #define E  X/4 +   ch/3
102 #define F -X/4 + 7*ch/12
103 #define G  4*X - 4*ch/3
104 #define H -4*X + 8*ch/3
105 #define a (y > 5*ch/9)
106 #define b (x < 4*cw/9)
107 #define c (x > 5*cw/9)
108 #define d (y < 4*ch/9)
109
110     /*
111       Each of these defines (except X which is just there for fun), represents
112       the equation of a line. The lines they represent are shown in the diagram
113       below. Checking y against these lines, we are able to choose a region
114       of the window as shown.
115
116       +---------------------A-------|-------|-------B---------------------+
117       |                     |A                     B|                     |
118       |                     |A      |       |      B|                     |
119       |                     | A                   B |                     |
120       |                     | A     |       |     B |                     |
121       |                     |  A                 B  |                     |
122       |                     |  A    |       |    B  |                     |
123       |        northwest    |   A     north     B   |   northeast         |
124       |                     |   A   |       |   B   |                     |
125       |                     |    A             B    |                     |
126       C---------------------+----A--+-------+--B----+---------------------D
127       |CCCCCCC              |     A           B     |              DDDDDDD|
128       |       CCCCCCCC      |     A |       | B     |      DDDDDDDD       |
129       |               CCCCCCC      A         B      DDDDDDD               |
130       - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
131       |                     |       b       c       |                     | sh
132       |             west    |       b  move c       |   east              | ad
133       |                     |       b       c       |                     | ed
134       - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - -  -
135       |               EEEEEEE      G         H      FFFFFFF               |
136       |       EEEEEEEE      |     G |       | H     |      FFFFFFFF       |
137       |EEEEEEE              |     G           H     |              FFFFFFF|
138       E---------------------+----G--+-------+--H----+---------------------F
139       |                     |    G             H    |                     |
140       |                     |   G   |       |   H   |                     |
141       |        southwest    |   G     south     H   |   southeast         |
142       |                     |  G    |       |    H  |                     |
143       |                     |  G                 H  |                     |
144       |                     | G     |       |     H |                     |
145       |                     | G                   H |                     |
146       |                     |G      |       |      H|                     |
147       |                     |G                     H|                     |
148       +---------------------G-------|-------|-------H---------------------+
149     */
150
151     if (shaded) {
152         /* for shaded windows, you can only resize west/east and move */
153         if (b)
154             return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT);
155         if (c)
156             return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT);
157         return OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE);
158     }
159
160     if (y < A && y >= C)
161         return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT);
162     else if (y >= A && y >= B && a)
163         return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP);
164     else if (y < B && y >= D)
165         return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT);
166     else if (y < C && y >= E && b)
167         return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT);
168     else if (y < D && y >= F && c)
169         return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT);
170     else if (y < E && y >= G)
171         return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT);
172     else if (y < G && y < H && d)
173         return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM);
174     else if (y >= H && y < F)
175         return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT);
176     else
177         return OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE);
178
179 #undef X
180 #undef A
181 #undef B
182 #undef C
183 #undef D
184 #undef E
185 #undef F
186 #undef G
187 #undef H
188 #undef a
189 #undef b
190 #undef c
191 #undef d
192 }