]> Dogcows Code - chaz/openbox/blob - openbox/moveresize.c
off by one caused clients to be resized a little during a move
[chaz/openbox] / openbox / moveresize.c
1 #include "grab.h"
2 #include "framerender.h"
3 #include "screen.h"
4 #include "prop.h"
5 #include "client.h"
6 #include "frame.h"
7 #include "openbox.h"
8 #include "resist.h"
9 #include "popup.h"
10 #include "moveresize.h"
11 #include "config.h"
12 #include "render/render.h"
13 #include "render/theme.h"
14
15 #include <X11/Xlib.h>
16 #include <glib.h>
17
18 gboolean moveresize_in_progress = FALSE;
19 ObClient *moveresize_client = NULL;
20
21 static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */
22
23 static int start_x, start_y, start_cx, start_cy, start_cw, start_ch;
24 static int cur_x, cur_y;
25 static guint button;
26 static guint32 corner;
27 static ObCorner lockcorner;
28
29 static Popup *popup = NULL;
30
31 static void client_dest(gpointer client)
32 {
33 if (moveresize_client == client)
34 moveresize_end(TRUE);
35 }
36
37 void moveresize_startup(gboolean reconfig)
38 {
39 popup = popup_new(FALSE);
40
41 if (!reconfig)
42 client_add_destructor(client_dest);
43 }
44
45 void moveresize_shutdown(gboolean reconfig)
46 {
47 if (!reconfig)
48 client_remove_destructor(client_dest);
49
50 popup_free(popup);
51 popup = NULL;
52 }
53
54 static void popup_coords(ObClient *c, char *format, int a, int b)
55 {
56 char *text;
57
58 text = g_strdup_printf(format, a, b);
59 popup_position(popup, CenterGravity,
60 c->frame->area.x + c->frame->size.left +
61 c->area.width / 2,
62 c->frame->area.y + c->frame->size.top +
63 c->area.height / 2);
64 popup_show(popup, text, NULL);
65 g_free(text);
66 }
67
68 void moveresize_start(ObClient *c, int x, int y, guint b, guint32 cnr)
69 {
70 ObCursor cur;
71
72 g_assert(!moveresize_in_progress);
73
74 if (!c->frame->visible)
75 return;
76
77 moveresize_client = c;
78 start_cx = c->frame->area.x;
79 start_cy = c->frame->area.y;
80 /* these adjustments for the size_inc make resizing a terminal more
81 friendly. you essentially start the resize in the middle of the
82 increment instead of at 0, so you have to move half an increment
83 either way instead of a full increment one and 1 px the other. and this
84 is one large mother fucking comment. */
85 start_cw = c->area.width + c->size_inc.width / 2;
86 start_ch = c->area.height + c->size_inc.height / 2;
87 start_x = x;
88 start_y = y;
89 corner = cnr;
90 button = b;
91
92 /*
93 have to change start_cx and start_cy if going to do this..
94 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
95 corner == prop_atoms.net_wm_moveresize_size_keyboard)
96 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
97 c->area.width / 2, c->area.height / 2);
98 */
99
100 if (corner == prop_atoms.net_wm_moveresize_move ||
101 corner == prop_atoms.net_wm_moveresize_move_keyboard) {
102 cur_x = start_cx;
103 cur_y = start_cy;
104 moving = TRUE;
105 } else {
106 cur_x = start_cw;
107 cur_y = start_ch;
108 moving = FALSE;
109 }
110
111 moveresize_in_progress = TRUE;
112
113 if (corner == prop_atoms.net_wm_moveresize_size_topleft)
114 cur = OB_CURSOR_NORTHWEST;
115 else if (corner == prop_atoms.net_wm_moveresize_size_top)
116 cur = OB_CURSOR_NORTH;
117 else if (corner == prop_atoms.net_wm_moveresize_size_topright)
118 cur = OB_CURSOR_NORTHEAST;
119 else if (corner == prop_atoms.net_wm_moveresize_size_right)
120 cur = OB_CURSOR_EAST;
121 else if (corner == prop_atoms.net_wm_moveresize_size_bottomright)
122 cur = OB_CURSOR_SOUTHEAST;
123 else if (corner == prop_atoms.net_wm_moveresize_size_bottom)
124 cur = OB_CURSOR_SOUTH;
125 else if (corner == prop_atoms.net_wm_moveresize_size_bottomleft)
126 cur = OB_CURSOR_SOUTHWEST;
127 else if (corner == prop_atoms.net_wm_moveresize_size_left)
128 cur = OB_CURSOR_WEST;
129 else if (corner == prop_atoms.net_wm_moveresize_size_keyboard)
130 cur = OB_CURSOR_SOUTHEAST;
131 else if (corner == prop_atoms.net_wm_moveresize_move)
132 cur = OB_CURSOR_MOVE;
133 else if (corner == prop_atoms.net_wm_moveresize_move_keyboard)
134 cur = OB_CURSOR_MOVE;
135 else
136 g_assert_not_reached();
137
138 grab_pointer(TRUE, cur);
139 grab_keyboard(TRUE);
140 }
141
142 void moveresize_end(gboolean cancel)
143 {
144 grab_keyboard(FALSE);
145 grab_pointer(FALSE, OB_CURSOR_NONE);
146
147 popup_hide(popup);
148
149 if (moving) {
150 client_move(moveresize_client,
151 (cancel ? start_cx : cur_x),
152 (cancel ? start_cy : cur_y));
153 } else {
154 client_configure(moveresize_client, lockcorner,
155 moveresize_client->area.x,
156 moveresize_client->area.y,
157 (cancel ? start_cw : cur_x),
158 (cancel ? start_ch : cur_y), TRUE, TRUE);
159 }
160
161 moveresize_in_progress = FALSE;
162 moveresize_client = NULL;
163 }
164
165 static void do_move(gboolean resist)
166 {
167 if (resist)
168 resist_move_windows(moveresize_client, &cur_x, &cur_y);
169 resist_move_monitors(moveresize_client, &cur_x, &cur_y);
170
171 /* get where the client should be */
172 frame_frame_gravity(moveresize_client->frame, &cur_x, &cur_y);
173 client_configure(moveresize_client, OB_CORNER_TOPLEFT, cur_x, cur_y,
174 start_cw, start_ch, TRUE, FALSE);
175 }
176
177 static void do_resize(gboolean resist)
178 {
179 /* resist_size_* needs the frame size */
180 cur_x += moveresize_client->frame->size.left +
181 moveresize_client->frame->size.right;
182 cur_y += moveresize_client->frame->size.top +
183 moveresize_client->frame->size.bottom;
184
185 if (resist)
186 resist_size_windows(moveresize_client, &cur_x, &cur_y, lockcorner);
187 resist_size_monitors(moveresize_client, &cur_x, &cur_y, lockcorner);
188
189 cur_x -= moveresize_client->frame->size.left +
190 moveresize_client->frame->size.right;
191 cur_y -= moveresize_client->frame->size.top +
192 moveresize_client->frame->size.bottom;
193
194 client_configure(moveresize_client, lockcorner,
195 moveresize_client->area.x, moveresize_client->area.y,
196 cur_x, cur_y, TRUE, FALSE);
197
198 /* this would be better with a fixed width font ... XXX can do it better
199 if there are 2 text boxes */
200 if (moveresize_client->size_inc.width > 1 ||
201 moveresize_client->size_inc.height > 1)
202 popup_coords(moveresize_client, "%d x %d",
203 moveresize_client->logical_size.width,
204 moveresize_client->logical_size.height);
205 }
206
207 void moveresize_event(XEvent *e)
208 {
209 g_assert(moveresize_in_progress);
210
211 if (e->type == ButtonPress) {
212 if (!button) {
213 start_x = e->xbutton.x_root;
214 start_y = e->xbutton.y_root;
215 button = e->xbutton.button; /* this will end it now */
216 }
217 } else if (e->type == ButtonRelease) {
218 if (!button || e->xbutton.button == button) {
219 moveresize_end(FALSE);
220 }
221 } else if (e->type == MotionNotify) {
222 if (moving) {
223 cur_x = start_cx + e->xmotion.x_root - start_x;
224 cur_y = start_cy + e->xmotion.y_root - start_y;
225 do_move(TRUE);
226 } else {
227 if (corner == prop_atoms.net_wm_moveresize_size_topleft) {
228 cur_x = start_cw - (e->xmotion.x_root - start_x);
229 cur_y = start_ch - (e->xmotion.y_root - start_y);
230 lockcorner = OB_CORNER_BOTTOMRIGHT;
231 } else if (corner == prop_atoms.net_wm_moveresize_size_top) {
232 cur_x = start_cw;
233 cur_y = start_ch - (e->xmotion.y_root - start_y);
234 lockcorner = OB_CORNER_BOTTOMRIGHT;
235 } else if (corner == prop_atoms.net_wm_moveresize_size_topright) {
236 cur_x = start_cw + (e->xmotion.x_root - start_x);
237 cur_y = start_ch - (e->xmotion.y_root - start_y);
238 lockcorner = OB_CORNER_BOTTOMLEFT;
239 } else if (corner == prop_atoms.net_wm_moveresize_size_right) {
240 cur_x = start_cw + (e->xmotion.x_root - start_x);
241 cur_y = start_ch;
242 lockcorner = OB_CORNER_BOTTOMLEFT;
243 } else if (corner ==
244 prop_atoms.net_wm_moveresize_size_bottomright) {
245 cur_x = start_cw + (e->xmotion.x_root - start_x);
246 cur_y = start_ch + (e->xmotion.y_root - start_y);
247 lockcorner = OB_CORNER_TOPLEFT;
248 } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) {
249 cur_x = start_cw;
250 cur_y = start_ch + (e->xmotion.y_root - start_y);
251 lockcorner = OB_CORNER_TOPLEFT;
252 } else if (corner ==
253 prop_atoms.net_wm_moveresize_size_bottomleft) {
254 cur_x = start_cw - (e->xmotion.x_root - start_x);
255 cur_y = start_ch + (e->xmotion.y_root - start_y);
256 lockcorner = OB_CORNER_TOPRIGHT;
257 } else if (corner == prop_atoms.net_wm_moveresize_size_left) {
258 cur_x = start_cw - (e->xmotion.x_root - start_x);
259 cur_y = start_ch;
260 lockcorner = OB_CORNER_TOPRIGHT;
261 } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
262 cur_x = start_cw + (e->xmotion.x_root - start_x);
263 cur_y = start_ch + (e->xmotion.y_root - start_y);
264 lockcorner = OB_CORNER_TOPLEFT;
265 } else
266 g_assert_not_reached();
267
268 do_resize(TRUE);
269 }
270 } else if (e->type == KeyPress) {
271 if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE))
272 moveresize_end(TRUE);
273 else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN))
274 moveresize_end(FALSE);
275 else {
276 if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
277 int dx = 0, dy = 0, ox = cur_x, oy = cur_y;
278
279 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
280 dx = MAX(4, moveresize_client->size_inc.width);
281 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
282 dx = -MAX(4, moveresize_client->size_inc.width);
283 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
284 dy = MAX(4, moveresize_client->size_inc.height);
285 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
286 dy = -MAX(4, moveresize_client->size_inc.height);
287 else
288 return;
289
290 cur_x += dx;
291 cur_y += dy;
292 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
293 /* steal the motion events this causes */
294 XSync(ob_display, FALSE);
295 {
296 XEvent ce;
297 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
298 }
299
300 do_resize(FALSE);
301
302 /* because the cursor moves even though the window does
303 not nessesarily (resistance), this adjusts where the curor
304 thinks it started so that it keeps up with where the window
305 actually is */
306 start_x += dx - (cur_x - ox);
307 start_y += dy - (cur_y - oy);
308 } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
309 int dx = 0, dy = 0, ox = cur_x, oy = cur_y;
310 int opx, px, opy, py;
311
312 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
313 dx = 4;
314 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
315 dx = -4;
316 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
317 dy = 4;
318 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
319 dy = -4;
320 else
321 return;
322
323 cur_x += dx;
324 cur_y += dy;
325 screen_pointer_pos(&opx, &opy);
326 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
327 /* steal the motion events this causes */
328 XSync(ob_display, FALSE);
329 {
330 XEvent ce;
331 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
332 }
333 screen_pointer_pos(&px, &py);
334
335 do_move(FALSE);
336
337 /* because the cursor moves even though the window does
338 not nessesarily (resistance), this adjusts where the curor
339 thinks it started so that it keeps up with where the window
340 actually is */
341 start_x += (px - opx) - (cur_x - ox);
342 start_y += (py - opy) - (cur_y - oy);
343 }
344 }
345 }
346 }
This page took 0.049389 seconds and 5 git commands to generate.