the resistance resizing has been changed from "lock corner" to "the direction being...
[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, cur_w, cur_h;
55 static guint button;
56 static guint32 corner;
57 static ObDirection edge_warp_dir = -1;
58 static ObDirection key_resize_edge = -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 #ifdef SYNC
68 static gboolean sync_timeout_func(gpointer data);
69 #endif
70
71 static void client_dest(ObClient *client, gpointer data)
72 {
73     if (moveresize_client == client)
74         moveresize_end(TRUE);
75 }
76
77 void moveresize_startup(gboolean reconfig)
78 {
79     popup = popup_new(FALSE);
80     popup_set_text_align(popup, RR_JUSTIFY_CENTER);
81
82     if (!reconfig)
83         client_add_destroy_notify(client_dest, NULL);
84 }
85
86 void moveresize_shutdown(gboolean reconfig)
87 {
88     if (!reconfig) {
89         if (moveresize_in_progress)
90             moveresize_end(FALSE);
91         client_remove_destroy_notify(client_dest);
92     }
93
94     popup_free(popup);
95     popup = NULL;
96 }
97
98 static void popup_coords(ObClient *c, const gchar *format, gint a, gint b)
99 {
100     gchar *text;
101
102     text = g_strdup_printf(format, a, b);
103     if (config_resize_popup_pos == 1) /* == "Top" */
104         popup_position(popup, SouthGravity,
105                        c->frame->area.x
106                      + c->frame->area.width/2,
107                        c->frame->area.y - ob_rr_theme->fbwidth);
108     else /* == "Center" */
109         popup_position(popup, CenterGravity,
110                        c->frame->area.x + c->frame->size.left +
111                        c->area.width / 2,
112                        c->frame->area.y + c->frame->size.top +
113                        c->area.height / 2);
114     popup_show(popup, text);
115     g_free(text);
116 }
117
118 void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
119 {
120     ObCursor cur;
121     gboolean mv = (cnr == prop_atoms.net_wm_moveresize_move ||
122                    cnr == prop_atoms.net_wm_moveresize_move_keyboard);
123
124     if (moveresize_in_progress || !c->frame->visible ||
125         !(mv ?
126           (c->functions & OB_CLIENT_FUNC_MOVE) :
127           (c->functions & OB_CLIENT_FUNC_RESIZE)))
128         return;
129
130     if (cnr == prop_atoms.net_wm_moveresize_size_topleft)
131         cur = OB_CURSOR_NORTHWEST;
132     else if (cnr == prop_atoms.net_wm_moveresize_size_top)
133         cur = OB_CURSOR_NORTH;
134     else if (cnr == prop_atoms.net_wm_moveresize_size_topright)
135         cur = OB_CURSOR_NORTHEAST;
136     else if (cnr == prop_atoms.net_wm_moveresize_size_right)
137         cur = OB_CURSOR_EAST;
138     else if (cnr == prop_atoms.net_wm_moveresize_size_bottomright)
139         cur = OB_CURSOR_SOUTHEAST;
140     else if (cnr == prop_atoms.net_wm_moveresize_size_bottom)
141         cur = OB_CURSOR_SOUTH;
142     else if (cnr == prop_atoms.net_wm_moveresize_size_bottomleft)
143         cur = OB_CURSOR_SOUTHWEST;
144     else if (cnr == prop_atoms.net_wm_moveresize_size_left)
145         cur = OB_CURSOR_WEST;
146     else if (cnr == prop_atoms.net_wm_moveresize_size_keyboard)
147         cur = OB_CURSOR_SOUTHEAST;
148     else if (cnr == prop_atoms.net_wm_moveresize_move)
149         cur = OB_CURSOR_MOVE;
150     else if (cnr == prop_atoms.net_wm_moveresize_move_keyboard)
151         cur = OB_CURSOR_MOVE;
152     else
153         g_assert_not_reached();
154
155     /* keep the pointer bounded to the screen for move/resize */
156     if (!grab_pointer(FALSE, TRUE, cur))
157         return;
158     if (!grab_keyboard()) {
159         ungrab_pointer();
160         return;
161     }
162
163     frame_end_iconify_animation(c->frame);
164
165     moving = mv;
166     moveresize_client = c;
167     start_cx = c->area.x;
168     start_cy = c->area.y;
169     start_cw = c->area.width;
170     start_ch = c->area.height;
171     /* these adjustments for the size_inc make resizing a terminal more
172        friendly. you essentially start the resize in the middle of the
173        increment instead of at 0, so you have to move half an increment
174        either way instead of a full increment one and 1 px the other. */
175     start_x = x - (mv ? 0 : c->size_inc.width / 2);
176     start_y = y - (mv ? 0 : c->size_inc.height / 2);
177     corner = cnr;
178     button = b;
179     key_resize_edge = -1;
180
181     /*
182       have to change start_cx and start_cy if going to do this..
183     if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
184         corner == prop_atoms.net_wm_moveresize_size_keyboard)
185         XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
186                      c->area.width / 2, c->area.height / 2);
187     */
188
189     cur_x = start_cx;
190     cur_y = start_cy;
191     cur_w = start_cw;
192     cur_h = start_ch;
193
194     moveresize_in_progress = TRUE;
195
196 #ifdef SYNC
197     if (config_resize_redraw && !moving && extensions_sync &&
198         moveresize_client->sync_request && moveresize_client->sync_counter)
199     {
200         /* Initialize values for the resize syncing, and create an alarm for
201            the client's xsync counter */
202
203         XSyncValue val;
204         XSyncAlarmAttributes aa;
205
206         /* set the counter to an initial value */
207         XSyncIntToValue(&val, 0);
208         XSyncSetCounter(ob_display, moveresize_client->sync_counter, val);
209
210         /* this will be incremented when we tell the client what we're
211            looking for */
212         moveresize_client->sync_counter_value = 0;
213
214         /* the next sequence we're waiting for with the alarm */
215         XSyncIntToValue(&val, 1);
216
217         /* set an alarm on the counter */
218         aa.trigger.counter = moveresize_client->sync_counter;
219         aa.trigger.wait_value = val;
220         aa.trigger.value_type = XSyncAbsolute;
221         aa.trigger.test_type = XSyncPositiveTransition;
222         aa.events = True;
223         XSyncIntToValue(&aa.delta, 1);
224         moveresize_alarm = XSyncCreateAlarm(ob_display,
225                                             XSyncCACounter |
226                                             XSyncCAValue |
227                                             XSyncCAValueType |
228                                             XSyncCATestType |
229                                             XSyncCADelta |
230                                             XSyncCAEvents,
231                                             &aa);
232
233         waiting_for_sync = FALSE;
234     }
235 #endif
236 }
237
238 void moveresize_end(gboolean cancel)
239 {
240     ungrab_keyboard();
241     ungrab_pointer();
242
243     popup_hide(popup);
244
245     if (moving) {
246         client_move(moveresize_client,
247                     (cancel ? start_cx : cur_x),
248                     (cancel ? start_cy : cur_y));
249     } else {
250 #ifdef SYNC
251         /* turn off the alarm */
252         if (moveresize_alarm != None) {
253             XSyncDestroyAlarm(ob_display, moveresize_alarm);
254             moveresize_alarm = None;
255         }
256
257         ob_main_loop_timeout_remove(ob_main_loop, sync_timeout_func);
258 #endif
259
260         client_configure(moveresize_client,
261                          (cancel ? start_cx : cur_x),
262                          (cancel ? start_cy : cur_y),
263                          (cancel ? start_cw : cur_w),
264                          (cancel ? start_ch : cur_h),
265                          TRUE, TRUE, FALSE);
266     }
267
268     /* dont edge warp after its ended */
269     cancel_edge_warp();
270
271     moveresize_in_progress = FALSE;
272     moveresize_client = NULL;
273 }
274
275 static void do_move(gboolean keyboard, gint keydist)
276 {
277     gint resist;
278
279     if (keyboard) resist = keydist - 1; /* resist for one key press */
280     else resist = config_resist_win;
281     resist_move_windows(moveresize_client, resist, &cur_x, &cur_y);
282     if (!keyboard) resist = config_resist_edge;
283     resist_move_monitors(moveresize_client, resist, &cur_x, &cur_y);
284
285     client_configure(moveresize_client, cur_x, cur_y, cur_w, cur_h,
286                      TRUE, FALSE, FALSE);
287     if (config_resize_popup_show == 2) /* == "Always" */
288         popup_coords(moveresize_client, "%d x %d",
289                      moveresize_client->frame->area.x,
290                      moveresize_client->frame->area.y);
291 }
292
293
294 static void do_resize()
295 {
296     gint x, y, w, h, lw, lh;
297
298     /* see if it is actually going to resize */
299     x = 0;
300     y = 0;
301     w = cur_w;
302     h = cur_h;
303     client_try_configure(moveresize_client, &x, &y, &w, &h,
304                          &lw, &lh, TRUE);
305     if (w == moveresize_client->area.width &&
306         h == moveresize_client->area.height)
307     {
308         return;
309     }
310
311 #ifdef SYNC
312     if (config_resize_redraw && extensions_sync &&
313         moveresize_client->sync_request && moveresize_client->sync_counter)
314     {
315         XEvent ce;
316         XSyncValue val;
317
318         /* are we already waiting for the sync counter to catch up? */
319         if (waiting_for_sync)
320             return;
321
322         /* increment the value we're waiting for */
323         ++moveresize_client->sync_counter_value;
324         XSyncIntToValue(&val, moveresize_client->sync_counter_value);
325
326         /* tell the client what we're waiting for */
327         ce.xclient.type = ClientMessage;
328         ce.xclient.message_type = prop_atoms.wm_protocols;
329         ce.xclient.display = ob_display;
330         ce.xclient.window = moveresize_client->window;
331         ce.xclient.format = 32;
332         ce.xclient.data.l[0] = prop_atoms.net_wm_sync_request;
333         ce.xclient.data.l[1] = event_curtime;
334         ce.xclient.data.l[2] = XSyncValueLow32(val);
335         ce.xclient.data.l[3] = XSyncValueHigh32(val);
336         ce.xclient.data.l[4] = 0l;
337         XSendEvent(ob_display, moveresize_client->window, FALSE,
338                    NoEventMask, &ce);
339
340         waiting_for_sync = TRUE;
341
342         ob_main_loop_timeout_remove(ob_main_loop, sync_timeout_func);
343         ob_main_loop_timeout_add(ob_main_loop, G_USEC_PER_SEC * 2,
344                                  sync_timeout_func,
345                                  NULL, NULL, NULL);
346     }
347 #endif
348
349     client_configure(moveresize_client, cur_x, cur_y, cur_w, cur_h,
350                      TRUE, FALSE, FALSE);
351
352     /* this would be better with a fixed width font ... XXX can do it better
353        if there are 2 text boxes */
354     if (config_resize_popup_show == 2 || /* == "Always" */
355             (config_resize_popup_show == 1 && /* == "Nonpixel" */
356              moveresize_client->size_inc.width > 1 &&
357              moveresize_client->size_inc.height > 1))
358         popup_coords(moveresize_client, "%d x %d",
359                      moveresize_client->logical_size.width,
360                      moveresize_client->logical_size.height);
361 }
362
363 #ifdef SYNC
364 static gboolean sync_timeout_func(gpointer data)
365 {
366     waiting_for_sync = FALSE; /* we timed out waiting for our sync... */
367     do_resize(); /* ...so let any pending resizes through */
368
369     return FALSE; /* don't repeat */
370 }
371 #endif
372
373 static void calc_resize(gboolean keyboard, gint keydist, gint *dw, gint *dh,
374                         ObDirection dir)
375 {
376     gint resist, x = 0, y = 0, lw, lh, ow, oh, nw, nh;
377
378     ow = cur_w;
379     oh = cur_h;
380     nw = ow + *dw;
381     nh = oh + *dh;
382
383     /* resist_size_* needs the frame size */
384     nw += moveresize_client->frame->size.left +
385         moveresize_client->frame->size.right;
386     nh += moveresize_client->frame->size.top +
387         moveresize_client->frame->size.bottom;
388
389     if (keyboard) resist = keydist - 1; /* resist for one key press */
390     else resist = config_resist_win;
391     resist_size_windows(moveresize_client, resist, &nw, &nh, dir);
392     if (!keyboard) resist = config_resist_edge;
393     resist_size_monitors(moveresize_client, resist, &nw, &nh, dir);
394
395     nw -= moveresize_client->frame->size.left +
396         moveresize_client->frame->size.right;
397     nh -= moveresize_client->frame->size.top +
398         moveresize_client->frame->size.bottom;
399
400     *dw = nw - ow;
401     *dh = nh - oh;
402
403     /* make sure it's a valid size */
404     client_try_configure(moveresize_client, &x, &y, &nw, &nh, &lw, &lh, TRUE);
405
406     *dw = nw - ow;
407     *dh = nh - oh;
408 }
409
410 static gboolean edge_warp_delay_func(gpointer data)
411 {
412     guint d;
413
414     d = screen_find_desktop(screen_desktop, edge_warp_dir, TRUE, FALSE);
415     if (d != screen_desktop) screen_set_desktop(d, TRUE);
416
417     edge_warp_dir = -1;
418
419     return FALSE; /* don't repeat */
420 }
421
422 static void do_edge_warp(gint x, gint y)
423 {
424     guint i;
425     ObDirection dir;
426
427     if (!config_mouse_screenedgetime) return;
428
429     dir = -1;
430
431     for (i = 0; i < screen_num_monitors; ++i) {
432         Rect *a = screen_physical_area_monitor(i);
433         if (x == RECT_LEFT(*a)) dir = OB_DIRECTION_WEST;
434         if (x == RECT_RIGHT(*a)) dir = OB_DIRECTION_EAST;
435         if (y == RECT_TOP(*a)) dir = OB_DIRECTION_NORTH;
436         if (y == RECT_BOTTOM(*a)) dir = OB_DIRECTION_SOUTH;
437
438         /* try check for xinerama boundaries */
439         if ((x + 1 == RECT_LEFT(*a) || x - 1 == RECT_RIGHT(*a)) &&
440             (dir == OB_DIRECTION_WEST || dir == OB_DIRECTION_EAST))
441         {
442             dir = -1;
443         }
444         if ((y + 1 == RECT_TOP(*a) || y - 1 == RECT_BOTTOM(*a)) &&
445             (dir == OB_DIRECTION_NORTH || dir == OB_DIRECTION_SOUTH))
446         {
447             dir = -1;
448         }
449         g_free(a);
450     }
451
452     if (dir != edge_warp_dir) {
453         if (dir == (ObDirection)-1)
454             cancel_edge_warp();
455         else
456             ob_main_loop_timeout_add(ob_main_loop,
457                                      config_mouse_screenedgetime * 1000,
458                                      edge_warp_delay_func,
459                                      NULL, NULL, NULL);
460         edge_warp_dir = dir;
461     }
462 }
463
464 static void cancel_edge_warp()
465 {
466     ob_main_loop_timeout_remove(ob_main_loop, edge_warp_delay_func);
467 }
468
469 static void move_with_keys(gint keycode, gint state)
470 {
471     gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
472     gint opx, px, opy, py;
473     gint dist = 0;
474
475     /* shift means jump to edge */
476     if (state & modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT)) {
477         gint x, y;
478         ObDirection dir;
479
480         if (keycode == ob_keycode(OB_KEY_RIGHT))
481             dir = OB_DIRECTION_EAST;
482         else if (keycode == ob_keycode(OB_KEY_LEFT))
483             dir = OB_DIRECTION_WEST;
484         else if (keycode == ob_keycode(OB_KEY_DOWN))
485             dir = OB_DIRECTION_SOUTH;
486         else /* if (keycode == ob_keycode(OB_KEY_UP)) */
487             dir = OB_DIRECTION_NORTH;
488
489         client_find_move_directional(moveresize_client, dir, &x, &y);
490         dx = x - moveresize_client->area.x;
491         dy = y - moveresize_client->area.y;
492     } else {
493         /* control means fine grained */
494         if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL))
495             dist = 1;
496         else
497             dist = KEY_DIST;
498
499         if (keycode == ob_keycode(OB_KEY_RIGHT))
500             dx = dist;
501         else if (keycode == ob_keycode(OB_KEY_LEFT))
502             dx = -dist;
503         else if (keycode == ob_keycode(OB_KEY_DOWN))
504             dy = dist;
505         else /* if (keycode == ob_keycode(OB_KEY_UP)) */
506             dy = -dist;
507     }
508
509     screen_pointer_pos(&opx, &opy);
510     XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
511     /* steal the motion events this causes */
512     XSync(ob_display, FALSE);
513     {
514         XEvent ce;
515         while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
516     }
517     screen_pointer_pos(&px, &py);
518
519     cur_x += dx;
520     cur_y += dy;
521     do_move(TRUE, dist);
522
523     /* because the cursor moves even though the window does
524        not nessesarily (resistance), this adjusts where the curor
525        thinks it started so that it keeps up with where the window
526        actually is */
527     start_x += (px - opx) - (cur_x - ox);
528     start_y += (py - opy) - (cur_y - oy);
529 }
530
531 static void resize_with_keys(gint keycode, gint state)
532 {
533     gint dw = 0, dh = 0, pdx = 0, pdy = 0, opx, opy, px, py;
534     gint dist = 0, resist = 0;
535     ObDirection dir;
536
537     /* pick the edge if it needs to move */
538     if (keycode == ob_keycode(OB_KEY_RIGHT)) {
539         dir = OB_DIRECTION_EAST;
540         if (key_resize_edge != OB_DIRECTION_WEST &&
541             key_resize_edge != OB_DIRECTION_EAST)
542         {
543             key_resize_edge = OB_DIRECTION_EAST;
544             return;
545         }
546     }
547     if (keycode == ob_keycode(OB_KEY_LEFT)) {
548         dir = OB_DIRECTION_WEST;
549         if (key_resize_edge != OB_DIRECTION_WEST &&
550             key_resize_edge != OB_DIRECTION_EAST)
551         {
552             key_resize_edge = OB_DIRECTION_WEST;
553             return;
554         }
555     }
556     if (keycode == ob_keycode(OB_KEY_UP)) {
557         dir = OB_DIRECTION_NORTH;
558         if (key_resize_edge != OB_DIRECTION_NORTH &&
559             key_resize_edge != OB_DIRECTION_SOUTH)
560         {
561             key_resize_edge = OB_DIRECTION_NORTH;
562             return;
563         }
564     }
565     if (keycode == ob_keycode(OB_KEY_DOWN)) {
566         dir = OB_DIRECTION_SOUTH;
567         if (key_resize_edge != OB_DIRECTION_NORTH &&
568             key_resize_edge != OB_DIRECTION_SOUTH)
569         {
570             key_resize_edge = OB_DIRECTION_SOUTH;
571             return;
572         }
573     }
574
575     /* shift means jump to edge */
576     if (state & modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT)) {
577         gint x, y, w, h;
578
579         if (keycode == ob_keycode(OB_KEY_RIGHT))
580             dir = OB_DIRECTION_EAST;
581         else if (keycode == ob_keycode(OB_KEY_LEFT))
582             dir = OB_DIRECTION_WEST;
583         else if (keycode == ob_keycode(OB_KEY_DOWN))
584             dir = OB_DIRECTION_SOUTH;
585         else /* if (keycode == ob_keycode(OB_KEY_UP)) */
586             dir = OB_DIRECTION_NORTH;
587
588         client_find_resize_directional(moveresize_client, key_resize_edge,
589                                        key_resize_edge == dir,
590                                        &x, &y, &w, &h);
591         dw = w - moveresize_client->area.width;
592         dh = h - moveresize_client->area.height;
593     } else {
594         gint distw, disth;
595
596         /* control means fine grained */
597         if (moveresize_client->size_inc.width > 1) {
598             distw = moveresize_client->size_inc.width;
599             resist = 1;
600         }
601         else if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL)) {
602             distw = 1;
603             resist = 1;
604         }
605         else {
606             distw = KEY_DIST;
607             resist = KEY_DIST;
608         }
609         if (moveresize_client->size_inc.height > 1) {
610             disth = moveresize_client->size_inc.height;
611             resist = 1;
612         }
613         else if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL)) {
614             disth = 1;
615             resist = 1;
616         }
617         else {
618             disth = KEY_DIST;
619             resist = KEY_DIST;
620         }
621
622         if (key_resize_edge == OB_DIRECTION_WEST) {
623             if (dir == OB_DIRECTION_WEST)
624                 dw = (dist = distw);
625             else
626                 dw = -(dist = distw);
627         }
628         else if (key_resize_edge == OB_DIRECTION_EAST) {
629             if (dir == OB_DIRECTION_EAST)
630                 dw = (dist = distw);
631             else
632                 dw = -(dist = distw);
633         }
634         else if (key_resize_edge == OB_DIRECTION_NORTH) {
635             if (dir == OB_DIRECTION_NORTH)
636                 dh = (dist = disth);
637             else
638                 dh = -(dist = disth);
639         }
640         else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
641             if (dir == OB_DIRECTION_SOUTH)
642                 dh = (dist = disth);
643             else
644                 dh = -(dist = disth);
645         }
646     }
647
648     calc_resize(TRUE, resist, &dw, &dh, dir);
649     if (key_resize_edge == OB_DIRECTION_WEST)
650         cur_x -= dw;
651     else if (key_resize_edge == OB_DIRECTION_NORTH)
652         cur_y -= dh;
653     cur_w += dw;
654     cur_h += dh;
655
656     /* how to move the pointer to keep up with the change */
657     if (key_resize_edge == OB_DIRECTION_WEST)
658         pdx = -dw;
659     else if (key_resize_edge == OB_DIRECTION_EAST)
660         pdx = dw;
661     else if (key_resize_edge == OB_DIRECTION_NORTH)
662         pdy = -dh;
663     else if (key_resize_edge == OB_DIRECTION_SOUTH)
664         pdy = dh;
665
666     screen_pointer_pos(&opx, &opy);
667     XWarpPointer(ob_display, None, None, 0, 0, 0, 0, pdx, pdy);
668     /* steal the motion events this causes */
669     XSync(ob_display, FALSE);
670     {
671         XEvent ce;
672         while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
673     }
674     screen_pointer_pos(&px, &py);
675
676     do_resize();
677
678     /* because the cursor moves even though the window does
679        not nessesarily (resistance), this adjusts where the cursor
680        thinks it started so that it keeps up with where the window
681        actually is */
682     start_x += (px - opx) - dw;
683     start_y += (py - opy) - dh;
684
685 }
686
687 gboolean moveresize_event(XEvent *e)
688 {
689     gboolean used = FALSE;
690
691     if (!moveresize_in_progress) return FALSE;
692
693     if (e->type == ButtonPress) {
694         if (!button) {
695             start_x = e->xbutton.x_root;
696             start_y = e->xbutton.y_root;
697             button = e->xbutton.button; /* this will end it now */
698         }
699         used = e->xbutton.button == button;
700     } else if (e->type == ButtonRelease) {
701         if (!button || e->xbutton.button == button) {
702             moveresize_end(FALSE);
703             used = TRUE;
704         }
705     } else if (e->type == MotionNotify) {
706         if (moving) {
707             cur_x = start_cx + e->xmotion.x_root - start_x;
708             cur_y = start_cy + e->xmotion.y_root - start_y;
709             do_move(FALSE, 0);
710             do_edge_warp(e->xmotion.x_root, e->xmotion.y_root);
711         } else {
712             gint dw, dh;
713             ObDirection dir;
714
715             if (corner == prop_atoms.net_wm_moveresize_size_topleft) {
716                 dw = -(e->xmotion.x_root - start_x);
717                 dh = -(e->xmotion.y_root - start_y);
718                 dir = OB_DIRECTION_NORTHWEST;
719             } else if (corner == prop_atoms.net_wm_moveresize_size_top) {
720                 dw = 0;
721                 dh = -(e->xmotion.y_root - start_y);
722                 dir = OB_DIRECTION_NORTH;
723             } else if (corner == prop_atoms.net_wm_moveresize_size_topright) {
724                 dw = (e->xmotion.x_root - start_x);
725                 dh = -(e->xmotion.y_root - start_y);
726                 dir = OB_DIRECTION_NORTHEAST;
727             } else if (corner == prop_atoms.net_wm_moveresize_size_right) {
728                 dw = (e->xmotion.x_root - start_x);
729                 dh = 0;
730                 dir = OB_DIRECTION_EAST;
731             } else if (corner ==
732                        prop_atoms.net_wm_moveresize_size_bottomright) {
733                 dw = (e->xmotion.x_root - start_x);
734                 dh = (e->xmotion.y_root - start_y);
735                 dir = OB_DIRECTION_SOUTHEAST;
736             } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) {
737                 dw = 0;
738                 dh = (e->xmotion.y_root - start_y);
739                 dir = OB_DIRECTION_SOUTH;
740             } else if (corner ==
741                        prop_atoms.net_wm_moveresize_size_bottomleft) {
742                 dw = -(e->xmotion.x_root - start_x);
743                 dh = (e->xmotion.y_root - start_y);
744                 dir = OB_DIRECTION_SOUTHWEST;
745             } else if (corner == prop_atoms.net_wm_moveresize_size_left) {
746                 dw = -(e->xmotion.x_root - start_x);
747                 dh = 0;
748                 dir = OB_DIRECTION_WEST;
749             } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
750                 dw = (e->xmotion.x_root - start_x);
751                 dh = (e->xmotion.y_root - start_y);
752                 dir = OB_DIRECTION_SOUTHEAST;
753             } else
754                 g_assert_not_reached();
755
756             dw -= cur_w - start_cw;
757             dh -= cur_h - start_ch;
758
759             calc_resize(FALSE, 0, &dw, &dh, dir);
760             cur_w += dw;
761             cur_h += dh;
762
763             if (corner == prop_atoms.net_wm_moveresize_size_topleft ||
764                 corner == prop_atoms.net_wm_moveresize_size_left ||
765                 corner == prop_atoms.net_wm_moveresize_size_bottomleft)
766             {
767                 cur_x -= dw;
768             }
769             if (corner == prop_atoms.net_wm_moveresize_size_topleft ||
770                 corner == prop_atoms.net_wm_moveresize_size_top ||
771                 corner == prop_atoms.net_wm_moveresize_size_topright)
772             {
773                 cur_y -= dh;
774             }
775
776             do_resize();
777         }
778         used = TRUE;
779     } else if (e->type == KeyPress) {
780         if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
781             moveresize_end(TRUE);
782             used = TRUE;
783         } else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
784             moveresize_end(FALSE);
785             used = TRUE;
786         } else if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT) ||
787                    e->xkey.keycode == ob_keycode(OB_KEY_LEFT) ||
788                    e->xkey.keycode == ob_keycode(OB_KEY_DOWN) ||
789                    e->xkey.keycode == ob_keycode(OB_KEY_UP))
790         {
791             if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
792                 resize_with_keys(e->xkey.keycode, e->xkey.state);
793                 used = TRUE;
794             } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
795                 move_with_keys(e->xkey.keycode, e->xkey.state);
796                 used = TRUE;
797             }
798         }
799     }
800 #ifdef SYNC
801     else if (e->type == extensions_sync_event_basep + XSyncAlarmNotify)
802     {
803         waiting_for_sync = FALSE; /* we got our sync... */
804         do_resize(); /* ...so try resize if there is more change pending */
805         used = TRUE;
806     }
807 #endif
808     return used;
809 }