1 #include "openbox/actions.h"
2 #include "openbox/moveresize.h"
3 #include "openbox/client.h"
4 #include "openbox/frame.h"
5 #include "openbox/screen.h"
9 gboolean corner_specified;
13 static gpointer setup_func(xmlNodePtr node);
14 static void free_func(gpointer o);
15 static gboolean run_func(ObActionsData *data, gpointer options);
17 static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch,
20 void action_resize_startup(void)
22 actions_register("Resize", setup_func, free_func, run_func);
25 static gpointer setup_func(xmlNodePtr node)
30 o = g_slice_new0(Options);
32 if ((n = obt_xml_find_node(node, "edge"))) {
33 gchar *s = obt_xml_node_string(n);
35 o->corner_specified = TRUE;
36 if (!g_ascii_strcasecmp(s, "top"))
37 o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP);
38 else if (!g_ascii_strcasecmp(s, "bottom"))
39 o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM);
40 else if (!g_ascii_strcasecmp(s, "left"))
41 o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT);
42 else if (!g_ascii_strcasecmp(s, "right"))
43 o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT);
44 else if (!g_ascii_strcasecmp(s, "topleft"))
45 o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT);
46 else if (!g_ascii_strcasecmp(s, "topright"))
47 o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT);
48 else if (!g_ascii_strcasecmp(s, "bottomleft"))
49 o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT);
50 else if (!g_ascii_strcasecmp(s, "bottomright"))
51 o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT);
53 o->corner_specified = FALSE;
60 static void free_func(gpointer o)
62 g_slice_free(Options, o);
65 /* Always return FALSE because its not interactive */
66 static gboolean run_func(ObActionsData *data, gpointer options)
71 ObClient *c = data->client;
75 corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD);
76 else if (o->corner_specified)
77 corner = o->corner; /* it was specified in the binding */
79 corner = pick_corner(data->x, data->y,
80 c->frame->area.x, c->frame->area.y,
81 /* use the client size because the frame
82 can be differently sized (shaded
83 windows) and we want this based on the
85 c->area.width + c->frame->size.left +
87 c->area.height + c->frame->size.top +
88 c->frame->size.bottom, c->shaded);
90 moveresize_start(c, data->x, data->y, data->button, corner);
96 static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch,
99 const Rect *full = screen_physical_area_all_monitors();
100 if (cx < full->x) { cw = cw + cx - full->x; cx = full->x; }
101 if (cy < full->y) { ch = ch + cy - full->y; cy = full->y; }
102 if (cx + cw > full->x + full->width) cw = full->x + full->width - cx;
103 if (cy + ch > full->y + full->height) ch = full->y + full->height - cy;
105 /* let's make x and y client relative instead of screen relative */
107 y = ch - (y - cy); /* y is inverted, 0 is at the bottom of the window */
110 #define A -4*X + 7*ch/3
111 #define B 4*X -15*ch/9
112 #define C -X/4 + 2*ch/3
113 #define D X/4 + 5*ch/12
115 #define F -X/4 + 7*ch/12
116 #define G 4*X - 4*ch/3
117 #define H -4*X + 8*ch/3
118 #define a (y > 5*ch/9)
119 #define b (x < 4*cw/9)
120 #define c (x > 5*cw/9)
121 #define d (y < 4*ch/9)
124 Each of these defines (except X which is just there for fun), represents
125 the equation of a line. The lines they represent are shown in the diagram
126 below. Checking y against these lines, we are able to choose a region
127 of the window as shown.
129 +---------------------A-------|-------|-------B---------------------+
136 | northwest | A north B | northeast |
139 C---------------------+----A--+-------+--B----+---------------------D
140 |CCCCCCC | A B | DDDDDDD|
141 | CCCCCCCC | A | | B | DDDDDDDD |
142 | CCCCCCC A B DDDDDDD |
143 - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
145 | west | b move c | east | ad
147 - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
148 | EEEEEEE G H FFFFFFF |
149 | EEEEEEEE | G | | H | FFFFFFFF |
150 |EEEEEEE | G H | FFFFFFF|
151 E---------------------+----G--+-------+--H----+---------------------F
154 | southwest | G south H | southeast |
161 +---------------------G-------|-------|-------H---------------------+
165 /* for shaded windows, you can only resize west/east and move */
167 return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT);
169 return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT);
170 return OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE);
174 return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT);
175 else if (y >= A && y >= B && a)
176 return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP);
177 else if (y < B && y >= D)
178 return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT);
179 else if (y < C && y >= E && b)
180 return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT);
181 else if (y < D && y >= F && c)
182 return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT);
183 else if (y < E && y >= G)
184 return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT);
185 else if (y < G && y < H && d)
186 return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM);
187 else if (y >= H && y < F)
188 return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT);
190 return OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE);