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