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