rewrote the movetoedge code so it works with both types of edges (to edge and from...
[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)
319 {
320     gint resist;
321
322     if (keyboard) resist = KEY_DIST - 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 gboolean moveresize_event(XEvent *e)
484 {
485     gboolean used = FALSE;
486
487     if (!moveresize_in_progress) return FALSE;
488
489     if (e->type == ButtonPress) {
490         if (!button) {
491             start_x = e->xbutton.x_root;
492             start_y = e->xbutton.y_root;
493             button = e->xbutton.button; /* this will end it now */
494         }
495         used = e->xbutton.button == button;
496     } else if (e->type == ButtonRelease) {
497         if (!button || e->xbutton.button == button) {
498             moveresize_end(FALSE);
499             used = TRUE;
500         }
501     } else if (e->type == MotionNotify) {
502         if (moving) {
503             cur_x = start_cx + e->xmotion.x_root - start_x;
504             cur_y = start_cy + e->xmotion.y_root - start_y;
505             do_move(FALSE);
506             do_edge_warp(e->xmotion.x_root, e->xmotion.y_root);
507         } else {
508             if (corner == prop_atoms.net_wm_moveresize_size_topleft) {
509                 cur_x = start_cw - (e->xmotion.x_root - start_x);
510                 cur_y = start_ch - (e->xmotion.y_root - start_y);
511                 lockcorner = OB_CORNER_BOTTOMRIGHT;
512             } else if (corner == prop_atoms.net_wm_moveresize_size_top) {
513                 cur_x = start_cw;
514                 cur_y = start_ch - (e->xmotion.y_root - start_y);
515                 lockcorner = OB_CORNER_BOTTOMRIGHT;
516             } else if (corner == prop_atoms.net_wm_moveresize_size_topright) {
517                 cur_x = start_cw + (e->xmotion.x_root - start_x);
518                 cur_y = start_ch - (e->xmotion.y_root - start_y);
519                 lockcorner = OB_CORNER_BOTTOMLEFT;
520             } else if (corner == prop_atoms.net_wm_moveresize_size_right) { 
521                 cur_x = start_cw + (e->xmotion.x_root - start_x);
522                 cur_y = start_ch;
523                 lockcorner = OB_CORNER_BOTTOMLEFT;
524             } else if (corner ==
525                        prop_atoms.net_wm_moveresize_size_bottomright) {
526                 cur_x = start_cw + (e->xmotion.x_root - start_x);
527                 cur_y = start_ch + (e->xmotion.y_root - start_y);
528                 lockcorner = OB_CORNER_TOPLEFT;
529             } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) {
530                 cur_x = start_cw;
531                 cur_y = start_ch + (e->xmotion.y_root - start_y);
532                 lockcorner = OB_CORNER_TOPLEFT;
533             } else if (corner ==
534                        prop_atoms.net_wm_moveresize_size_bottomleft) {
535                 cur_x = start_cw - (e->xmotion.x_root - start_x);
536                 cur_y = start_ch + (e->xmotion.y_root - start_y);
537                 lockcorner = OB_CORNER_TOPRIGHT;
538             } else if (corner == prop_atoms.net_wm_moveresize_size_left) {
539                 cur_x = start_cw - (e->xmotion.x_root - start_x);
540                 cur_y = start_ch;
541                 lockcorner = OB_CORNER_TOPRIGHT;
542             } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
543                 cur_x = start_cw + (e->xmotion.x_root - start_x);
544                 cur_y = start_ch + (e->xmotion.y_root - start_y);
545                 lockcorner = OB_CORNER_TOPLEFT;
546             } else
547                 g_assert_not_reached();
548
549             calc_resize(FALSE);
550             do_resize();
551         }
552         used = TRUE;
553     } else if (e->type == KeyPress) {
554         if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
555             moveresize_end(TRUE);
556             used = TRUE;
557         } else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
558             moveresize_end(FALSE);
559             used = TRUE;
560         } else if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT) ||
561                    e->xkey.keycode == ob_keycode(OB_KEY_LEFT) ||
562                    e->xkey.keycode == ob_keycode(OB_KEY_DOWN) ||
563                    e->xkey.keycode == ob_keycode(OB_KEY_UP))
564         {
565             if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
566                 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
567
568                 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
569                     dx = MAX(KEY_DIST, moveresize_client->size_inc.width);
570                 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
571                     dx = -MAX(KEY_DIST, moveresize_client->size_inc.width);
572                 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
573                     dy = MAX(KEY_DIST, moveresize_client->size_inc.height);
574                 else /* if (e->xkey.keycode == ob_keycode(OB_KEY_UP)) */
575                     dy = -MAX(KEY_DIST, moveresize_client->size_inc.height);
576
577                 cur_x += dx;
578                 cur_y += dy;
579                 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
580                 /* steal the motion events this causes */
581                 XSync(ob_display, FALSE);
582                 {
583                     XEvent ce;
584                     while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
585                 }
586
587                 calc_resize(TRUE);
588                 do_resize();
589
590                 /* because the cursor moves even though the window does
591                    not nessesarily (resistance), this adjusts where the curor
592                    thinks it started so that it keeps up with where the window
593                    actually is */
594                 start_x += dx - (cur_x - ox);
595                 start_y += dy - (cur_y - oy);
596
597                 used = TRUE;
598             } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
599                 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
600                 gint opx, px, opy, py;
601                 gint dist = KEY_DIST;
602
603                 /* shift means jump to edge */
604                 if (e->xkey.state & modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT)) {
605                     gint x, y;
606                     ObDirection dir;
607
608                     if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
609                         dir = OB_DIRECTION_EAST;
610                     else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
611                         dir = OB_DIRECTION_WEST;
612                     else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
613                         dir = OB_DIRECTION_SOUTH;
614                     else /* if (e->xkey.keycode == ob_keycode(OB_KEY_UP)) */
615                         dir = OB_DIRECTION_NORTH;
616
617                     client_find_move_directional(moveresize_client, dir,
618                                                  &x, &y);
619                     dx = x - moveresize_client->area.x;
620                     dy = y - moveresize_client->area.y;
621                 } else {
622                     /* control means fine grained */
623                     if (e->xkey.state &
624                         modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL))
625                         dist = 1;
626
627                     if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
628                         dx = dist;
629                     else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
630                         dx = -dist;
631                     else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
632                         dy = dist;
633                     else /* if (e->xkey.keycode == ob_keycode(OB_KEY_UP)) */
634                         dy = -dist;
635                 }
636
637                 cur_x += dx;
638                 cur_y += dy;
639                 screen_pointer_pos(&opx, &opy);
640                 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
641                 /* steal the motion events this causes */
642                 XSync(ob_display, FALSE);
643                 {
644                     XEvent ce;
645                     while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
646                 }
647                 screen_pointer_pos(&px, &py);
648
649                 do_move(TRUE);
650
651                 /* because the cursor moves even though the window does
652                    not nessesarily (resistance), this adjusts where the curor
653                    thinks it started so that it keeps up with where the window
654                    actually is */
655                 start_x += (px - opx) - (cur_x - ox);
656                 start_y += (py - opy) - (cur_y - oy);
657
658                 used = TRUE;
659             }
660         }
661     }
662 #ifdef SYNC
663     else if (e->type == extensions_sync_event_basep + XSyncAlarmNotify)
664     {
665         waiting_for_sync = FALSE; /* we got our sync... */
666         do_resize(); /* ...so try resize if there is more change pending */
667         used = TRUE;
668     }
669 #endif
670     return used;
671 }