or a full second?
[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, ow, oh, nw, nh;
378
379     /* resist_size_* needs the frame size */
380     ow = cur_w +
381         moveresize_client->frame->size.left +
382         moveresize_client->frame->size.right;
383     oh = cur_h +
384         moveresize_client->frame->size.top +
385         moveresize_client->frame->size.bottom;
386     nw = ow + *dw;
387     nh = oh + *dh;
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     *dw = nw - ow;
396     *dh = nh - oh;
397 }
398
399 static gboolean edge_warp_delay_func(gpointer data)
400 {
401     guint d;
402
403     d = screen_find_desktop(screen_desktop, edge_warp_dir, TRUE, FALSE);
404     if (d != screen_desktop) screen_set_desktop(d, TRUE);
405
406     edge_warp_dir = -1;
407
408     return FALSE; /* don't repeat */
409 }
410
411 static void do_edge_warp(gint x, gint y)
412 {
413     guint i;
414     ObDirection dir;
415
416     if (!config_mouse_screenedgetime) return;
417
418     dir = -1;
419
420     for (i = 0; i < screen_num_monitors; ++i) {
421         Rect *a = screen_physical_area_monitor(i);
422         if (x == RECT_LEFT(*a)) dir = OB_DIRECTION_WEST;
423         if (x == RECT_RIGHT(*a)) dir = OB_DIRECTION_EAST;
424         if (y == RECT_TOP(*a)) dir = OB_DIRECTION_NORTH;
425         if (y == RECT_BOTTOM(*a)) dir = OB_DIRECTION_SOUTH;
426
427         /* try check for xinerama boundaries */
428         if ((x + 1 == RECT_LEFT(*a) || x - 1 == RECT_RIGHT(*a)) &&
429             (dir == OB_DIRECTION_WEST || dir == OB_DIRECTION_EAST))
430         {
431             dir = -1;
432         }
433         if ((y + 1 == RECT_TOP(*a) || y - 1 == RECT_BOTTOM(*a)) &&
434             (dir == OB_DIRECTION_NORTH || dir == OB_DIRECTION_SOUTH))
435         {
436             dir = -1;
437         }
438         g_free(a);
439     }
440
441     if (dir != edge_warp_dir) {
442         if (dir == (ObDirection)-1)
443             cancel_edge_warp();
444         else
445             ob_main_loop_timeout_add(ob_main_loop,
446                                      config_mouse_screenedgetime * 1000,
447                                      edge_warp_delay_func,
448                                      NULL, NULL, NULL);
449         edge_warp_dir = dir;
450     }
451 }
452
453 static void cancel_edge_warp()
454 {
455     ob_main_loop_timeout_remove(ob_main_loop, edge_warp_delay_func);
456 }
457
458 static void move_with_keys(gint keycode, gint state)
459 {
460     gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
461     gint opx, px, opy, py;
462     gint dist = 0;
463
464     /* shift means jump to edge */
465     if (state & modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT)) {
466         gint x, y;
467         ObDirection dir;
468
469         if (keycode == ob_keycode(OB_KEY_RIGHT))
470             dir = OB_DIRECTION_EAST;
471         else if (keycode == ob_keycode(OB_KEY_LEFT))
472             dir = OB_DIRECTION_WEST;
473         else if (keycode == ob_keycode(OB_KEY_DOWN))
474             dir = OB_DIRECTION_SOUTH;
475         else /* if (keycode == ob_keycode(OB_KEY_UP)) */
476             dir = OB_DIRECTION_NORTH;
477
478         client_find_move_directional(moveresize_client, dir, &x, &y);
479         dx = x - moveresize_client->area.x;
480         dy = y - moveresize_client->area.y;
481     } else {
482         /* control means fine grained */
483         if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL))
484             dist = 1;
485         else
486             dist = KEY_DIST;
487
488         if (keycode == ob_keycode(OB_KEY_RIGHT))
489             dx = dist;
490         else if (keycode == ob_keycode(OB_KEY_LEFT))
491             dx = -dist;
492         else if (keycode == ob_keycode(OB_KEY_DOWN))
493             dy = dist;
494         else /* if (keycode == ob_keycode(OB_KEY_UP)) */
495             dy = -dist;
496     }
497
498     screen_pointer_pos(&opx, &opy);
499     XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
500     /* steal the motion events this causes */
501     XSync(ob_display, FALSE);
502     {
503         XEvent ce;
504         while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
505     }
506     screen_pointer_pos(&px, &py);
507
508     cur_x += dx;
509     cur_y += dy;
510     do_move(TRUE, dist);
511
512     /* because the cursor moves even though the window does
513        not nessesarily (resistance), this adjusts where the curor
514        thinks it started so that it keeps up with where the window
515        actually is */
516     start_x += (px - opx) - (cur_x - ox);
517     start_y += (py - opy) - (cur_y - oy);
518 }
519
520 static void resize_with_keys(gint keycode, gint state)
521 {
522     gint dw = 0, dh = 0, pdx = 0, pdy = 0, opx, opy, px, py;
523     gint dist = 0;
524     ObDirection dir;
525     ObCorner cor;
526
527     /* pick the edge if it needs to move */
528     if (keycode == ob_keycode(OB_KEY_RIGHT)) {
529         dir = OB_DIRECTION_EAST;
530         if (key_resize_edge != OB_DIRECTION_WEST &&
531             key_resize_edge != OB_DIRECTION_EAST)
532         {
533             key_resize_edge = OB_DIRECTION_EAST;
534             return;
535         }
536     }
537     if (keycode == ob_keycode(OB_KEY_LEFT)) {
538         dir = OB_DIRECTION_WEST;
539         if (key_resize_edge != OB_DIRECTION_WEST &&
540             key_resize_edge != OB_DIRECTION_EAST)
541         {
542             key_resize_edge = OB_DIRECTION_WEST;
543             return;
544         }
545     }
546     if (keycode == ob_keycode(OB_KEY_UP)) {
547         dir = OB_DIRECTION_NORTH;
548         if (key_resize_edge != OB_DIRECTION_NORTH &&
549             key_resize_edge != OB_DIRECTION_SOUTH)
550         {
551             key_resize_edge = OB_DIRECTION_NORTH;
552             return;
553         }
554     }
555     if (keycode == ob_keycode(OB_KEY_DOWN)) {
556         dir = OB_DIRECTION_SOUTH;
557         if (key_resize_edge != OB_DIRECTION_NORTH &&
558             key_resize_edge != OB_DIRECTION_SOUTH)
559         {
560             key_resize_edge = OB_DIRECTION_SOUTH;
561             return;
562         }
563     }
564
565     /* shift means jump to edge */
566     if (state & modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT)) {
567         gint x, y, w, h;
568
569         if (keycode == ob_keycode(OB_KEY_RIGHT))
570             dir = OB_DIRECTION_EAST;
571         else if (keycode == ob_keycode(OB_KEY_LEFT))
572             dir = OB_DIRECTION_WEST;
573         else if (keycode == ob_keycode(OB_KEY_DOWN))
574             dir = OB_DIRECTION_SOUTH;
575         else /* if (keycode == ob_keycode(OB_KEY_UP)) */
576             dir = OB_DIRECTION_NORTH;
577
578         client_find_resize_directional(moveresize_client, key_resize_edge,
579                                        key_resize_edge == dir,
580                                        &x, &y, &w, &h);
581         dw = w - moveresize_client->area.width;
582         dh = h - moveresize_client->area.height;
583     } else {
584         gint distw, disth;
585
586         /* control means fine grained */
587         if (moveresize_client->size_inc.width > 1)
588             distw = moveresize_client->size_inc.width;
589         else if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL))
590             distw = 1;
591         else
592             distw = KEY_DIST;
593         if (moveresize_client->size_inc.height > 1)
594             disth = moveresize_client->size_inc.height;
595         else if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL))
596             disth = 1;
597         else
598             disth = KEY_DIST;
599
600         if (key_resize_edge == OB_DIRECTION_WEST) {
601             if (dir == OB_DIRECTION_WEST)
602                 dw = (dist = distw);
603             else
604                 dw = -(dist = distw);
605         }
606         else if (key_resize_edge == OB_DIRECTION_EAST) {
607             if (dir == OB_DIRECTION_EAST)
608                 dw = (dist = distw);
609             else
610                 dw = -(dist = distw);
611         }
612         else if (key_resize_edge == OB_DIRECTION_NORTH) {
613             if (dir == OB_DIRECTION_NORTH)
614                 dh = (dist = disth);
615             else
616                 dh = -(dist = disth);
617         }
618         else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
619             if (dir == OB_DIRECTION_SOUTH)
620                 dh = (dist = disth);
621             else
622                 dh = -(dist = disth);
623         }
624     }
625
626     /* which corner is locked, for resistance */
627     if (key_resize_edge == OB_DIRECTION_WEST)
628         cor = OB_CORNER_TOPRIGHT;
629     else if (key_resize_edge == OB_DIRECTION_EAST)
630         cor = OB_CORNER_TOPLEFT;
631     else if (key_resize_edge == OB_DIRECTION_NORTH)
632         cor = OB_CORNER_BOTTOMLEFT;
633     else if (key_resize_edge == OB_DIRECTION_SOUTH)
634         cor = OB_CORNER_TOPLEFT;
635
636     calc_resize(TRUE, dist, &dw, &dh, cor);
637     if (key_resize_edge == OB_DIRECTION_WEST)
638         cur_x -= dw;
639     else if (key_resize_edge == OB_DIRECTION_NORTH)
640         cur_y -= dh;
641     cur_w += dw;
642     cur_h += dh;
643
644     /* how to move the pointer to keep up with the change */
645     if (key_resize_edge == OB_DIRECTION_WEST)
646         pdx = -dw;
647     else if (key_resize_edge == OB_DIRECTION_EAST)
648         pdx = dw;
649     else if (key_resize_edge == OB_DIRECTION_NORTH)
650         pdy = -dh;
651     else if (key_resize_edge == OB_DIRECTION_SOUTH)
652         pdy = dh;
653     
654     screen_pointer_pos(&opx, &opy);
655     XWarpPointer(ob_display, None, None, 0, 0, 0, 0, pdx, pdy);
656     /* steal the motion events this causes */
657     XSync(ob_display, FALSE);
658     {
659         XEvent ce;
660         while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
661     }
662     screen_pointer_pos(&px, &py);
663
664     do_resize();
665
666     /* because the cursor moves even though the window does
667        not nessesarily (resistance), this adjusts where the cursor
668        thinks it started so that it keeps up with where the window
669        actually is */
670     start_x += (px - opx) - dw;
671     start_y += (py - opy) - dh;
672
673 }
674
675 gboolean moveresize_event(XEvent *e)
676 {
677     gboolean used = FALSE;
678
679     if (!moveresize_in_progress) return FALSE;
680
681     if (e->type == ButtonPress) {
682         if (!button) {
683             start_x = e->xbutton.x_root;
684             start_y = e->xbutton.y_root;
685             button = e->xbutton.button; /* this will end it now */
686         }
687         used = e->xbutton.button == button;
688     } else if (e->type == ButtonRelease) {
689         if (!button || e->xbutton.button == button) {
690             moveresize_end(FALSE);
691             used = TRUE;
692         }
693     } else if (e->type == MotionNotify) {
694         if (moving) {
695             cur_x = start_cx + e->xmotion.x_root - start_x;
696             cur_y = start_cy + e->xmotion.y_root - start_y;
697             do_move(FALSE, 0);
698             do_edge_warp(e->xmotion.x_root, e->xmotion.y_root);
699         } else {
700             gint dw, dh;
701
702             if (corner == prop_atoms.net_wm_moveresize_size_topleft) {
703                 dw = -(e->xmotion.x_root - start_x);
704                 dh = -(e->xmotion.y_root - start_y);
705                 lockcorner = OB_CORNER_BOTTOMRIGHT;
706             } else if (corner == prop_atoms.net_wm_moveresize_size_top) {
707                 dw = 0;
708                 dh = (e->xmotion.y_root - start_y);
709                 lockcorner = OB_CORNER_BOTTOMRIGHT;
710             } else if (corner == prop_atoms.net_wm_moveresize_size_topright) {
711                 dw = (e->xmotion.x_root - start_x);
712                 dh = -(e->xmotion.y_root - start_y);
713                 lockcorner = OB_CORNER_BOTTOMLEFT;
714             } else if (corner == prop_atoms.net_wm_moveresize_size_right) { 
715                 dw = (e->xmotion.x_root - start_x);
716                 dh = 0;
717                 lockcorner = OB_CORNER_BOTTOMLEFT;
718             } else if (corner ==
719                        prop_atoms.net_wm_moveresize_size_bottomright) {
720                 dw = (e->xmotion.x_root - start_x);
721                 dh = (e->xmotion.y_root - start_y);
722                 lockcorner = OB_CORNER_TOPLEFT;
723             } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) {
724                 dw = 0;
725                 dh = (e->xmotion.y_root - start_y);
726                 lockcorner = OB_CORNER_TOPLEFT;
727             } else if (corner ==
728                        prop_atoms.net_wm_moveresize_size_bottomleft) {
729                 dw = -(e->xmotion.x_root - start_x);
730                 dh = (e->xmotion.y_root - start_y);
731                 lockcorner = OB_CORNER_TOPRIGHT;
732             } else if (corner == prop_atoms.net_wm_moveresize_size_left) {
733                 dw = -(e->xmotion.x_root - start_x);
734                 dh = 0;
735                 lockcorner = OB_CORNER_TOPRIGHT;
736             } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
737                 dw = (e->xmotion.x_root - start_x);
738                 dh = (e->xmotion.y_root - start_y);
739                 lockcorner = OB_CORNER_TOPLEFT;
740             } else
741                 g_assert_not_reached();
742
743             dw -= cur_w - start_cw;
744             dh -= cur_h - start_ch;
745
746             calc_resize(FALSE, 0, &dw, &dh, lockcorner);
747             cur_w += dw;
748             cur_h += dh;
749
750             if (corner == prop_atoms.net_wm_moveresize_size_topleft ||
751                 corner == prop_atoms.net_wm_moveresize_size_left ||
752                 corner == prop_atoms.net_wm_moveresize_size_bottomleft)
753             {
754                 cur_x -= dw;
755             }
756             if (corner == prop_atoms.net_wm_moveresize_size_topleft ||
757                 corner == prop_atoms.net_wm_moveresize_size_top ||
758                 corner == prop_atoms.net_wm_moveresize_size_topright)
759             {
760                 cur_y -= dh;
761             }
762
763             do_resize();
764         }
765         used = TRUE;
766     } else if (e->type == KeyPress) {
767         if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
768             moveresize_end(TRUE);
769             used = TRUE;
770         } else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
771             moveresize_end(FALSE);
772             used = TRUE;
773         } else if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT) ||
774                    e->xkey.keycode == ob_keycode(OB_KEY_LEFT) ||
775                    e->xkey.keycode == ob_keycode(OB_KEY_DOWN) ||
776                    e->xkey.keycode == ob_keycode(OB_KEY_UP))
777         {
778             if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
779                 resize_with_keys(e->xkey.keycode, e->xkey.state);
780                 used = TRUE;
781             } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
782                 move_with_keys(e->xkey.keycode, e->xkey.state);
783                 used = TRUE;
784             }
785         }
786     }
787 #ifdef SYNC
788     else if (e->type == extensions_sync_event_basep + XSyncAlarmNotify)
789     {
790         waiting_for_sync = FALSE; /* we got our sync... */
791         do_resize(); /* ...so try resize if there is more change pending */
792         used = TRUE;
793     }
794 #endif
795     return used;
796 }