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