move keyboard moving into its own function
[dana/openbox.git] / openbox / moveresize.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    moveresize.c for the Openbox window manager
4    Copyright (c) 2006        Mikael Magnusson
5    Copyright (c) 2003-2007   Dana Jansens
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "grab.h"
21 #include "framerender.h"
22 #include "screen.h"
23 #include "prop.h"
24 #include "client.h"
25 #include "frame.h"
26 #include "openbox.h"
27 #include "resist.h"
28 #include "mainloop.h"
29 #include "modkeys.h"
30 #include "popup.h"
31 #include "moveresize.h"
32 #include "config.h"
33 #include "event.h"
34 #include "debug.h"
35 #include "extensions.h"
36 #include "render/render.h"
37 #include "render/theme.h"
38
39 #include <X11/Xlib.h>
40 #include <glib.h>
41
42 /* how far windows move and resize with the keyboard arrows */
43 #define KEY_DIST 8
44
45 gboolean moveresize_in_progress = FALSE;
46 ObClient *moveresize_client = NULL;
47 #ifdef SYNC
48 XSyncAlarm moveresize_alarm = None;
49 #endif
50
51 static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */
52
53 static gint start_x, start_y, start_cx, start_cy, start_cw, start_ch;
54 static gint cur_x, cur_y;
55 static guint button;
56 static guint32 corner;
57 static ObCorner lockcorner;
58 static ObDirection edge_warp_dir = -1;
59 #ifdef SYNC
60 static gboolean waiting_for_sync;
61 #endif
62
63 static ObPopup *popup = NULL;
64
65 static void do_edge_warp(gint x, gint y);
66 static void cancel_edge_warp();
67
68 static void client_dest(ObClient *client, gpointer data)
69 {
70     if (moveresize_client == client)
71         moveresize_end(TRUE);    
72 }
73
74 void moveresize_startup(gboolean reconfig)
75 {
76     popup = popup_new(FALSE);
77     popup_set_text_align(popup, RR_JUSTIFY_CENTER);
78
79     if (!reconfig)
80         client_add_destroy_notify(client_dest, NULL);
81 }
82
83 void moveresize_shutdown(gboolean reconfig)
84 {
85     if (!reconfig) {
86         if (moveresize_in_progress)
87             moveresize_end(FALSE);
88         client_remove_destroy_notify(client_dest);
89     }
90
91     popup_free(popup);
92     popup = NULL;
93 }
94
95 static void get_resize_position(gint *x, gint *y, gboolean cancel)
96 {
97     gint dw, dh;
98     gint w, h, lw, lh;
99
100     *x = moveresize_client->frame->area.x;
101     *y = moveresize_client->frame->area.y;
102
103     if (cancel) {
104         w = start_cw;
105         h = start_ch;
106     } else {
107         w = cur_x;
108         h = cur_y;
109     }
110
111     /* see how much it is actually going to resize */
112     {
113         gint cx = *x, cy = *y;
114         frame_frame_gravity(moveresize_client->frame, &cx, &cy);
115         client_try_configure(moveresize_client, &cx, &cy, &w, &h,
116                              &lw, &lh, TRUE);
117     }
118     dw = w - moveresize_client->area.width;
119     dh = h - moveresize_client->area.height;
120
121     switch (lockcorner) {
122     case OB_CORNER_TOPLEFT:
123         break;
124     case OB_CORNER_TOPRIGHT:
125         *x -= dw;
126         break;
127     case OB_CORNER_BOTTOMLEFT:
128         *y -= dh;
129         break;
130     case OB_CORNER_BOTTOMRIGHT:
131         *x -= dw;
132         *y -= dh;
133         break;
134     }
135
136     frame_frame_gravity(moveresize_client->frame, x, y);
137 }
138
139 static void popup_coords(ObClient *c, const gchar *format, gint a, gint b)
140 {
141     gchar *text;
142
143     text = g_strdup_printf(format, a, b);
144     if (config_resize_popup_pos == 1) /* == "Top" */
145         popup_position(popup, SouthGravity,
146                        c->frame->area.x
147                      + c->frame->area.width/2,
148                        c->frame->area.y - ob_rr_theme->fbwidth);
149     else /* == "Center" */
150         popup_position(popup, CenterGravity,
151                        c->frame->area.x + c->frame->size.left +
152                        c->area.width / 2,
153                        c->frame->area.y + c->frame->size.top +
154                        c->area.height / 2);
155     popup_show(popup, text);
156     g_free(text);
157 }
158
159 void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
160 {
161     ObCursor cur;
162     gboolean mv = (cnr == prop_atoms.net_wm_moveresize_move ||
163                    cnr == prop_atoms.net_wm_moveresize_move_keyboard);
164
165     if (moveresize_in_progress || !c->frame->visible ||
166         !(mv ?
167           (c->functions & OB_CLIENT_FUNC_MOVE) :
168           (c->functions & OB_CLIENT_FUNC_RESIZE)))
169         return;
170
171     if (cnr == prop_atoms.net_wm_moveresize_size_topleft)
172         cur = OB_CURSOR_NORTHWEST;
173     else if (cnr == prop_atoms.net_wm_moveresize_size_top)
174         cur = OB_CURSOR_NORTH;
175     else if (cnr == prop_atoms.net_wm_moveresize_size_topright)
176         cur = OB_CURSOR_NORTHEAST;
177     else if (cnr == prop_atoms.net_wm_moveresize_size_right)
178         cur = OB_CURSOR_EAST;
179     else if (cnr == prop_atoms.net_wm_moveresize_size_bottomright)
180         cur = OB_CURSOR_SOUTHEAST;
181     else if (cnr == prop_atoms.net_wm_moveresize_size_bottom)
182         cur = OB_CURSOR_SOUTH;
183     else if (cnr == prop_atoms.net_wm_moveresize_size_bottomleft)
184         cur = OB_CURSOR_SOUTHWEST;
185     else if (cnr == prop_atoms.net_wm_moveresize_size_left)
186         cur = OB_CURSOR_WEST;
187     else if (cnr == prop_atoms.net_wm_moveresize_size_keyboard)
188         cur = OB_CURSOR_SOUTHEAST;
189     else if (cnr == prop_atoms.net_wm_moveresize_move)
190         cur = OB_CURSOR_MOVE;
191     else if (cnr == prop_atoms.net_wm_moveresize_move_keyboard)
192         cur = OB_CURSOR_MOVE;
193     else
194         g_assert_not_reached();
195
196     /* keep the pointer bounded to the screen for move/resize */
197     if (!grab_pointer(FALSE, TRUE, cur))
198         return;
199     if (!grab_keyboard()) {
200         ungrab_pointer();
201         return;
202     }
203
204     frame_end_iconify_animation(c->frame);
205
206     moving = mv;
207     moveresize_client = c;
208     start_cx = c->area.x;
209     start_cy = c->area.y;
210     /* these adjustments for the size_inc make resizing a terminal more
211        friendly. you essentially start the resize in the middle of the
212        increment instead of at 0, so you have to move half an increment
213        either way instead of a full increment one and 1 px the other. and this
214        is one large mother fucking comment. */
215     start_cw = c->area.width + c->size_inc.width / 2;
216     start_ch = c->area.height + c->size_inc.height / 2;
217     start_x = x;
218     start_y = y;
219     corner = cnr;
220     button = b;
221
222     /*
223       have to change start_cx and start_cy if going to do this..
224     if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
225         corner == prop_atoms.net_wm_moveresize_size_keyboard)
226         XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
227                      c->area.width / 2, c->area.height / 2);
228     */
229
230     if (moving) {
231         cur_x = start_cx;
232         cur_y = start_cy;
233     } else {
234         cur_x = start_cw;
235         cur_y = start_ch;
236     }
237
238     moveresize_in_progress = TRUE;
239
240 #ifdef SYNC
241     if (config_resize_redraw && !moving && extensions_shape &&
242         moveresize_client->sync_request && moveresize_client->sync_counter)
243     {
244         /* Initialize values for the resize syncing, and create an alarm for
245            the client's xsync counter */
246
247         XSyncValue val;
248         XSyncAlarmAttributes aa;
249
250         /* set the counter to an initial value */
251         XSyncIntToValue(&val, 0);
252         XSyncSetCounter(ob_display, moveresize_client->sync_counter, val);
253
254         /* this will be incremented when we tell the client what we're
255            looking for */
256         moveresize_client->sync_counter_value = 0;
257
258         /* the next sequence we're waiting for with the alarm */
259         XSyncIntToValue(&val, 1);
260
261         /* set an alarm on the counter */
262         aa.trigger.counter = moveresize_client->sync_counter;
263         aa.trigger.wait_value = val;
264         aa.trigger.value_type = XSyncAbsolute;
265         aa.trigger.test_type = XSyncPositiveTransition;
266         aa.events = True;
267         XSyncIntToValue(&aa.delta, 1);
268         moveresize_alarm = XSyncCreateAlarm(ob_display,
269                                             XSyncCACounter |
270                                             XSyncCAValue |
271                                             XSyncCAValueType |
272                                             XSyncCATestType |
273                                             XSyncCADelta |
274                                             XSyncCAEvents,
275                                             &aa);
276
277         waiting_for_sync = FALSE;
278     }
279 #endif
280 }
281
282 void moveresize_end(gboolean cancel)
283 {
284     gint x, y;
285
286     ungrab_keyboard();
287     ungrab_pointer();
288
289     popup_hide(popup);
290
291     if (moving) {
292         client_move(moveresize_client,
293                     (cancel ? start_cx : cur_x),
294                     (cancel ? start_cy : cur_y));
295     } else {
296 #ifdef SYNC
297         /* turn off the alarm */
298         if (moveresize_alarm != None) {
299             XSyncDestroyAlarm(ob_display, moveresize_alarm);
300             moveresize_alarm = None;
301         }
302 #endif
303
304         get_resize_position(&x, &y, cancel);
305         client_configure(moveresize_client, x, y,
306                          (cancel ? start_cw : cur_x),
307                          (cancel ? start_ch : cur_y),
308                          TRUE, TRUE, FALSE);
309     }
310
311     /* dont edge warp after its ended */
312     cancel_edge_warp();
313
314     moveresize_in_progress = FALSE;
315     moveresize_client = NULL;
316 }
317
318 static void do_move(gboolean keyboard, gint keydist)
319 {
320     gint resist;
321
322     if (keyboard) resist = keydist - 1; /* resist for one key press */
323     else resist = config_resist_win;
324     resist_move_windows(moveresize_client, resist, &cur_x, &cur_y);
325     if (!keyboard) resist = config_resist_edge;
326     resist_move_monitors(moveresize_client, resist, &cur_x, &cur_y);
327
328     client_configure(moveresize_client, cur_x, cur_y,
329                      moveresize_client->area.width,
330                      moveresize_client->area.height,
331                      TRUE, FALSE, FALSE);
332     if (config_resize_popup_show == 2) /* == "Always" */
333         popup_coords(moveresize_client, "%d x %d",
334                      moveresize_client->frame->area.x,
335                      moveresize_client->frame->area.y);
336 }
337
338 static void do_resize()
339 {
340     gint x, y, w, h, lw, lh;
341
342     /* see if it is actually going to resize */
343     x = 0;
344     y = 0;
345     w = cur_x;
346     h = cur_y;
347     client_try_configure(moveresize_client, &x, &y, &w, &h,
348                          &lw, &lh, TRUE);
349     if (w == moveresize_client->area.width &&
350         h == moveresize_client->area.height)
351     {
352         return;
353     }
354
355 #ifdef SYNC
356     if (config_resize_redraw && extensions_sync &&
357         moveresize_client->sync_request && moveresize_client->sync_counter)
358     {
359         XEvent ce;
360         XSyncValue val;
361
362         /* are we already waiting for the sync counter to catch up? */
363         if (waiting_for_sync)
364             return;
365
366         /* increment the value we're waiting for */
367         ++moveresize_client->sync_counter_value;
368         XSyncIntToValue(&val, moveresize_client->sync_counter_value);
369
370         /* tell the client what we're waiting for */
371         ce.xclient.type = ClientMessage;
372         ce.xclient.message_type = prop_atoms.wm_protocols;
373         ce.xclient.display = ob_display;
374         ce.xclient.window = moveresize_client->window;
375         ce.xclient.format = 32;
376         ce.xclient.data.l[0] = prop_atoms.net_wm_sync_request;
377         ce.xclient.data.l[1] = event_curtime;
378         ce.xclient.data.l[2] = XSyncValueLow32(val);
379         ce.xclient.data.l[3] = XSyncValueHigh32(val);
380         ce.xclient.data.l[4] = 0l;
381         XSendEvent(ob_display, moveresize_client->window, FALSE,
382                    NoEventMask, &ce);
383
384         waiting_for_sync = TRUE;
385     }
386 #endif
387
388     get_resize_position(&x, &y, FALSE);
389     client_configure(moveresize_client, x, y, cur_x, cur_y, TRUE, FALSE, FALSE);
390
391     /* this would be better with a fixed width font ... XXX can do it better
392        if there are 2 text boxes */
393     if (config_resize_popup_show == 2 || /* == "Always" */
394             (config_resize_popup_show == 1 && /* == "Nonpixel" */
395              moveresize_client->size_inc.width > 1 &&
396              moveresize_client->size_inc.height > 1))
397         popup_coords(moveresize_client, "%d x %d",
398                      moveresize_client->logical_size.width,
399                      moveresize_client->logical_size.height);
400 }
401
402 static void calc_resize(gboolean keyboard)
403 {
404     gint resist;
405
406     /* resist_size_* needs the frame size */
407     cur_x += moveresize_client->frame->size.left +
408         moveresize_client->frame->size.right;
409     cur_y += moveresize_client->frame->size.top +
410         moveresize_client->frame->size.bottom;
411
412     if (keyboard) resist = KEY_DIST - 1; /* resist for one key press */
413     else resist = config_resist_win;
414     resist_size_windows(moveresize_client, resist, &cur_x, &cur_y, lockcorner);
415     if (!keyboard) resist = config_resist_edge;
416     resist_size_monitors(moveresize_client, resist, &cur_x, &cur_y,lockcorner);
417
418     cur_x -= moveresize_client->frame->size.left +
419         moveresize_client->frame->size.right;
420     cur_y -= moveresize_client->frame->size.top +
421         moveresize_client->frame->size.bottom;
422 }
423
424 static gboolean edge_warp_delay_func(gpointer data)
425 {
426     guint d;
427
428     d = screen_find_desktop(screen_desktop, edge_warp_dir, TRUE, FALSE);
429     if (d != screen_desktop) screen_set_desktop(d, TRUE);
430
431     edge_warp_dir = -1;
432
433     return FALSE; /* don't repeat */
434 }
435
436 static void do_edge_warp(gint x, gint y)
437 {
438     guint i;
439     ObDirection dir;
440
441     if (!config_mouse_screenedgetime) return;
442
443     dir = -1;
444
445     for (i = 0; i < screen_num_monitors; ++i) {
446         Rect *a = screen_physical_area_monitor(i);
447         if (x == RECT_LEFT(*a)) dir = OB_DIRECTION_WEST;
448         if (x == RECT_RIGHT(*a)) dir = OB_DIRECTION_EAST;
449         if (y == RECT_TOP(*a)) dir = OB_DIRECTION_NORTH;
450         if (y == RECT_BOTTOM(*a)) dir = OB_DIRECTION_SOUTH;
451
452         /* try check for xinerama boundaries */
453         if ((x + 1 == RECT_LEFT(*a) || x - 1 == RECT_RIGHT(*a)) &&
454             (dir == OB_DIRECTION_WEST || dir == OB_DIRECTION_EAST))
455         {
456             dir = -1;
457         }
458         if ((y + 1 == RECT_TOP(*a) || y - 1 == RECT_BOTTOM(*a)) &&
459             (dir == OB_DIRECTION_NORTH || dir == OB_DIRECTION_SOUTH))
460         {
461             dir = -1;
462         }
463         g_free(a);
464     }
465
466     if (dir != edge_warp_dir) {
467         if (dir == (ObDirection)-1)
468             cancel_edge_warp();
469         else
470             ob_main_loop_timeout_add(ob_main_loop,
471                                      config_mouse_screenedgetime * 1000,
472                                      edge_warp_delay_func,
473                                      NULL, NULL, NULL);
474         edge_warp_dir = dir;
475     }
476 }
477
478 static void cancel_edge_warp()
479 {
480     ob_main_loop_timeout_remove(ob_main_loop, edge_warp_delay_func);
481 }
482
483 static void move_with_keys(gint keycode, gint state)
484 {
485     gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
486     gint opx, px, opy, py;
487     gint dist = 0;
488
489     /* shift means jump to edge */
490     if (state & modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT)) {
491         gint x, y;
492         ObDirection dir;
493
494         if (keycode == ob_keycode(OB_KEY_RIGHT))
495             dir = OB_DIRECTION_EAST;
496         else if (keycode == ob_keycode(OB_KEY_LEFT))
497             dir = OB_DIRECTION_WEST;
498         else if (keycode == ob_keycode(OB_KEY_DOWN))
499             dir = OB_DIRECTION_SOUTH;
500         else /* if (keycode == ob_keycode(OB_KEY_UP)) */
501             dir = OB_DIRECTION_NORTH;
502
503         client_find_move_directional(moveresize_client, dir, &x, &y);
504         dx = x - moveresize_client->area.x;
505         dy = y - moveresize_client->area.y;
506     } else {
507         /* control means fine grained */
508         if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL))
509             dist = 1;
510         else
511             dist = KEY_DIST;
512
513         if (keycode == ob_keycode(OB_KEY_RIGHT))
514             dx = dist;
515         else if (keycode == ob_keycode(OB_KEY_LEFT))
516             dx = -dist;
517         else if (keycode == ob_keycode(OB_KEY_DOWN))
518             dy = dist;
519         else /* if (keycode == ob_keycode(OB_KEY_UP)) */
520             dy = -dist;
521     }
522
523     screen_pointer_pos(&opx, &opy);
524     XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
525     /* steal the motion events this causes */
526     XSync(ob_display, FALSE);
527     {
528         XEvent ce;
529         while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
530     }
531     screen_pointer_pos(&px, &py);
532
533     cur_x += dx;
534     cur_y += dy;
535     do_move(TRUE, dist);
536
537     /* because the cursor moves even though the window does
538        not nessesarily (resistance), this adjusts where the curor
539        thinks it started so that it keeps up with where the window
540        actually is */
541     start_x += (px - opx) - (cur_x - ox);
542     start_y += (py - opy) - (cur_y - oy);
543 }
544
545 gboolean moveresize_event(XEvent *e)
546 {
547     gboolean used = FALSE;
548
549     if (!moveresize_in_progress) return FALSE;
550
551     if (e->type == ButtonPress) {
552         if (!button) {
553             start_x = e->xbutton.x_root;
554             start_y = e->xbutton.y_root;
555             button = e->xbutton.button; /* this will end it now */
556         }
557         used = e->xbutton.button == button;
558     } else if (e->type == ButtonRelease) {
559         if (!button || e->xbutton.button == button) {
560             moveresize_end(FALSE);
561             used = TRUE;
562         }
563     } else if (e->type == MotionNotify) {
564         if (moving) {
565             cur_x = start_cx + e->xmotion.x_root - start_x;
566             cur_y = start_cy + e->xmotion.y_root - start_y;
567             do_move(FALSE, 0);
568             do_edge_warp(e->xmotion.x_root, e->xmotion.y_root);
569         } else {
570             if (corner == prop_atoms.net_wm_moveresize_size_topleft) {
571                 cur_x = start_cw - (e->xmotion.x_root - start_x);
572                 cur_y = start_ch - (e->xmotion.y_root - start_y);
573                 lockcorner = OB_CORNER_BOTTOMRIGHT;
574             } else if (corner == prop_atoms.net_wm_moveresize_size_top) {
575                 cur_x = start_cw;
576                 cur_y = start_ch - (e->xmotion.y_root - start_y);
577                 lockcorner = OB_CORNER_BOTTOMRIGHT;
578             } else if (corner == prop_atoms.net_wm_moveresize_size_topright) {
579                 cur_x = start_cw + (e->xmotion.x_root - start_x);
580                 cur_y = start_ch - (e->xmotion.y_root - start_y);
581                 lockcorner = OB_CORNER_BOTTOMLEFT;
582             } else if (corner == prop_atoms.net_wm_moveresize_size_right) { 
583                 cur_x = start_cw + (e->xmotion.x_root - start_x);
584                 cur_y = start_ch;
585                 lockcorner = OB_CORNER_BOTTOMLEFT;
586             } else if (corner ==
587                        prop_atoms.net_wm_moveresize_size_bottomright) {
588                 cur_x = start_cw + (e->xmotion.x_root - start_x);
589                 cur_y = start_ch + (e->xmotion.y_root - start_y);
590                 lockcorner = OB_CORNER_TOPLEFT;
591             } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) {
592                 cur_x = start_cw;
593                 cur_y = start_ch + (e->xmotion.y_root - start_y);
594                 lockcorner = OB_CORNER_TOPLEFT;
595             } else if (corner ==
596                        prop_atoms.net_wm_moveresize_size_bottomleft) {
597                 cur_x = start_cw - (e->xmotion.x_root - start_x);
598                 cur_y = start_ch + (e->xmotion.y_root - start_y);
599                 lockcorner = OB_CORNER_TOPRIGHT;
600             } else if (corner == prop_atoms.net_wm_moveresize_size_left) {
601                 cur_x = start_cw - (e->xmotion.x_root - start_x);
602                 cur_y = start_ch;
603                 lockcorner = OB_CORNER_TOPRIGHT;
604             } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
605                 cur_x = start_cw + (e->xmotion.x_root - start_x);
606                 cur_y = start_ch + (e->xmotion.y_root - start_y);
607                 lockcorner = OB_CORNER_TOPLEFT;
608             } else
609                 g_assert_not_reached();
610
611             calc_resize(FALSE);
612             do_resize();
613         }
614         used = TRUE;
615     } else if (e->type == KeyPress) {
616         if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
617             moveresize_end(TRUE);
618             used = TRUE;
619         } else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
620             moveresize_end(FALSE);
621             used = TRUE;
622         } else if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT) ||
623                    e->xkey.keycode == ob_keycode(OB_KEY_LEFT) ||
624                    e->xkey.keycode == ob_keycode(OB_KEY_DOWN) ||
625                    e->xkey.keycode == ob_keycode(OB_KEY_UP))
626         {
627             if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
628                 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
629
630                 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
631                     dx = MAX(KEY_DIST, moveresize_client->size_inc.width);
632                 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
633                     dx = -MAX(KEY_DIST, moveresize_client->size_inc.width);
634                 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
635                     dy = MAX(KEY_DIST, moveresize_client->size_inc.height);
636                 else /* if (e->xkey.keycode == ob_keycode(OB_KEY_UP)) */
637                     dy = -MAX(KEY_DIST, moveresize_client->size_inc.height);
638
639                 cur_x += dx;
640                 cur_y += dy;
641                 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
642                 /* steal the motion events this causes */
643                 XSync(ob_display, FALSE);
644                 {
645                     XEvent ce;
646                     while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
647                 }
648
649                 calc_resize(TRUE);
650                 do_resize();
651
652                 /* because the cursor moves even though the window does
653                    not nessesarily (resistance), this adjusts where the curor
654                    thinks it started so that it keeps up with where the window
655                    actually is */
656                 start_x += dx - (cur_x - ox);
657                 start_y += dy - (cur_y - oy);
658
659                 used = TRUE;
660             } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
661                 move_with_keys(e->xkey.keycode, e->xkey.state);
662                 used = TRUE;
663             }
664         }
665     }
666 #ifdef SYNC
667     else if (e->type == extensions_sync_event_basep + XSyncAlarmNotify)
668     {
669         waiting_for_sync = FALSE; /* we got our sync... */
670         do_resize(); /* ...so try resize if there is more change pending */
671         used = TRUE;
672     }
673 #endif
674     return used;
675 }