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