use the hover and press button colors (this was a bug)
[openbox.git] / openbox / moveresize.c
blob9374f8b5f77930e96eb37828540a2d9daf2181ee
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 moveresize.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
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.
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.
17 See the COPYING file for a copy of the GNU General Public License.
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"
39 #include <X11/Xlib.h>
40 #include <glib.h>
42 /* how far windows move and resize with the keyboard arrows */
43 #define KEY_DIST 8
45 gboolean moveresize_in_progress = FALSE;
46 ObClient *moveresize_client = NULL;
47 #ifdef SYNC
48 XSyncAlarm moveresize_alarm = None;
49 #endif
51 static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */
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 gboolean edge_warp_odd = FALSE;
59 static ObDirection key_resize_edge = -1;
60 #ifdef SYNC
61 static gboolean waiting_for_sync;
62 #endif
64 static ObPopup *popup = NULL;
66 static void do_edge_warp(gint x, gint y);
67 static void cancel_edge_warp();
68 #ifdef SYNC
69 static gboolean sync_timeout_func(gpointer data);
70 #endif
72 static void client_dest(ObClient *client, gpointer data)
74 if (moveresize_client == client)
75 moveresize_end(TRUE);
78 void moveresize_startup(gboolean reconfig)
80 popup = popup_new();
81 popup_set_text_align(popup, RR_JUSTIFY_CENTER);
83 if (!reconfig)
84 client_add_destroy_notify(client_dest, NULL);
87 void moveresize_shutdown(gboolean reconfig)
89 if (!reconfig) {
90 if (moveresize_in_progress)
91 moveresize_end(FALSE);
92 client_remove_destroy_notify(client_dest);
95 popup_free(popup);
96 popup = NULL;
99 static void popup_coords(ObClient *c, const gchar *format, gint a, gint b)
101 gchar *text;
103 text = g_strdup_printf(format, a, b);
104 if (config_resize_popup_pos == OB_RESIZE_POS_TOP)
105 popup_position(popup, SouthGravity,
106 c->frame->area.x
107 + c->frame->area.width/2,
108 c->frame->area.y - ob_rr_theme->fbwidth);
109 else if (config_resize_popup_pos == OB_RESIZE_POS_CENTER)
110 popup_position(popup, CenterGravity,
111 c->frame->area.x + c->frame->size.left +
112 c->area.width / 2,
113 c->frame->area.y + c->frame->size.top +
114 c->area.height / 2);
115 else /* Fixed */ {
116 Rect *area = screen_physical_area_active();
117 gint gravity, x, y;
119 x = config_resize_popup_fixed.x.pos;
120 if (config_resize_popup_fixed.x.center)
121 x = area->x + area->width/2;
122 else if (config_resize_popup_fixed.x.opposite)
123 x = RECT_RIGHT(*area) - x;
124 else
125 x = area->x + x;
127 y = config_resize_popup_fixed.y.pos;
128 if (config_resize_popup_fixed.y.center)
129 y = area->y + area->height/2;
130 else if (config_resize_popup_fixed.y.opposite)
131 y = RECT_RIGHT(*area) - y;
132 else
133 y = area->y + y;
135 if (config_resize_popup_fixed.x.center) {
136 if (config_resize_popup_fixed.y.center)
137 gravity = CenterGravity;
138 else if (config_resize_popup_fixed.y.opposite)
139 gravity = SouthGravity;
140 else
141 gravity = NorthGravity;
143 else if (config_resize_popup_fixed.x.opposite) {
144 if (config_resize_popup_fixed.y.center)
145 gravity = EastGravity;
146 else if (config_resize_popup_fixed.y.opposite)
147 gravity = SouthEastGravity;
148 else
149 gravity = NorthEastGravity;
151 else {
152 if (config_resize_popup_fixed.y.center)
153 gravity = WestGravity;
154 else if (config_resize_popup_fixed.y.opposite)
155 gravity = SouthWestGravity;
156 else
157 gravity = NorthWestGravity;
160 popup_position(popup, gravity, x, y);
162 g_free(area);
164 popup_show(popup, text);
165 g_free(text);
168 void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
170 ObCursor cur;
171 gboolean mv = (cnr == prop_atoms.net_wm_moveresize_move ||
172 cnr == prop_atoms.net_wm_moveresize_move_keyboard);
173 gint up = 1;
174 gint left = 1;
176 if (moveresize_in_progress || !c->frame->visible ||
177 !(mv ?
178 (c->functions & OB_CLIENT_FUNC_MOVE) :
179 (c->functions & OB_CLIENT_FUNC_RESIZE)))
180 return;
182 if (cnr == prop_atoms.net_wm_moveresize_size_topleft) {
183 cur = OB_CURSOR_NORTHWEST;
184 up = left = -1;
185 } else if (cnr == prop_atoms.net_wm_moveresize_size_top) {
186 cur = OB_CURSOR_NORTH;
187 up = -1;
188 } else if (cnr == prop_atoms.net_wm_moveresize_size_topright) {
189 cur = OB_CURSOR_NORTHEAST;
190 up = -1;
191 } else if (cnr == prop_atoms.net_wm_moveresize_size_right)
192 cur = OB_CURSOR_EAST;
193 else if (cnr == prop_atoms.net_wm_moveresize_size_bottomright)
194 cur = OB_CURSOR_SOUTHEAST;
195 else if (cnr == prop_atoms.net_wm_moveresize_size_bottom)
196 cur = OB_CURSOR_SOUTH;
197 else if (cnr == prop_atoms.net_wm_moveresize_size_bottomleft) {
198 cur = OB_CURSOR_SOUTHWEST;
199 left = -1;
200 } else if (cnr == prop_atoms.net_wm_moveresize_size_left) {
201 cur = OB_CURSOR_WEST;
202 left = -1;
203 } else if (cnr == prop_atoms.net_wm_moveresize_size_keyboard)
204 cur = OB_CURSOR_SOUTHEAST;
205 else if (cnr == prop_atoms.net_wm_moveresize_move)
206 cur = OB_CURSOR_MOVE;
207 else if (cnr == prop_atoms.net_wm_moveresize_move_keyboard)
208 cur = OB_CURSOR_MOVE;
209 else
210 g_assert_not_reached();
212 /* keep the pointer bounded to the screen for move/resize */
213 if (!grab_pointer(FALSE, TRUE, cur))
214 return;
215 if (!grab_keyboard()) {
216 ungrab_pointer();
217 return;
220 frame_end_iconify_animation(c->frame);
222 moving = mv;
223 moveresize_client = c;
224 start_cx = c->area.x;
225 start_cy = c->area.y;
226 start_cw = c->area.width;
227 start_ch = c->area.height;
228 /* these adjustments for the size_inc make resizing a terminal more
229 friendly. you essentially start the resize in the middle of the
230 increment instead of at 0, so you have to move half an increment
231 either way instead of a full increment one and 1 px the other. */
232 start_x = x - (mv ? 0 : left * c->size_inc.width / 2);
233 start_y = y - (mv ? 0 : up * c->size_inc.height / 2);
234 corner = cnr;
235 button = b;
236 key_resize_edge = -1;
239 have to change start_cx and start_cy if going to do this..
240 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
241 corner == prop_atoms.net_wm_moveresize_size_keyboard)
242 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
243 c->area.width / 2, c->area.height / 2);
246 cur_x = start_cx;
247 cur_y = start_cy;
248 cur_w = start_cw;
249 cur_h = start_ch;
251 moveresize_in_progress = TRUE;
253 #ifdef SYNC
254 if (config_resize_redraw && !moving && extensions_sync &&
255 moveresize_client->sync_request && moveresize_client->sync_counter &&
256 !moveresize_client->not_responding)
258 /* Initialize values for the resize syncing, and create an alarm for
259 the client's xsync counter */
261 XSyncValue val;
262 XSyncAlarmAttributes aa;
264 /* set the counter to an initial value */
265 XSyncIntToValue(&val, 0);
266 XSyncSetCounter(ob_display, moveresize_client->sync_counter, val);
268 /* this will be incremented when we tell the client what we're
269 looking for */
270 moveresize_client->sync_counter_value = 0;
272 /* the next sequence we're waiting for with the alarm */
273 XSyncIntToValue(&val, 1);
275 /* set an alarm on the counter */
276 aa.trigger.counter = moveresize_client->sync_counter;
277 aa.trigger.wait_value = val;
278 aa.trigger.value_type = XSyncAbsolute;
279 aa.trigger.test_type = XSyncPositiveTransition;
280 aa.events = True;
281 XSyncIntToValue(&aa.delta, 1);
282 moveresize_alarm = XSyncCreateAlarm(ob_display,
283 XSyncCACounter |
284 XSyncCAValue |
285 XSyncCAValueType |
286 XSyncCATestType |
287 XSyncCADelta |
288 XSyncCAEvents,
289 &aa);
291 waiting_for_sync = FALSE;
293 #endif
296 void moveresize_end(gboolean cancel)
298 ungrab_keyboard();
299 ungrab_pointer();
301 popup_hide(popup);
303 if (moving) {
304 client_move(moveresize_client,
305 (cancel ? start_cx : cur_x),
306 (cancel ? start_cy : cur_y));
307 } else {
308 #ifdef SYNC
309 /* turn off the alarm */
310 if (moveresize_alarm != None) {
311 XSyncDestroyAlarm(ob_display, moveresize_alarm);
312 moveresize_alarm = None;
315 ob_main_loop_timeout_remove(ob_main_loop, sync_timeout_func);
316 #endif
318 client_configure(moveresize_client,
319 (cancel ? start_cx : cur_x),
320 (cancel ? start_cy : cur_y),
321 (cancel ? start_cw : cur_w),
322 (cancel ? start_ch : cur_h),
323 TRUE, TRUE, FALSE);
326 /* dont edge warp after its ended */
327 cancel_edge_warp();
329 moveresize_in_progress = FALSE;
330 moveresize_client = NULL;
333 static void do_move(gboolean keyboard, gint keydist)
335 gint resist;
337 if (keyboard) resist = keydist - 1; /* resist for one key press */
338 else resist = config_resist_win;
339 resist_move_windows(moveresize_client, resist, &cur_x, &cur_y);
340 if (!keyboard) resist = config_resist_edge;
341 resist_move_monitors(moveresize_client, resist, &cur_x, &cur_y);
343 client_configure(moveresize_client, cur_x, cur_y, cur_w, cur_h,
344 TRUE, FALSE, FALSE);
345 if (config_resize_popup_show == 2) /* == "Always" */
346 popup_coords(moveresize_client, "%d x %d",
347 moveresize_client->frame->area.x,
348 moveresize_client->frame->area.y);
352 static void do_resize(void)
354 gint x, y, w, h, lw, lh;
356 /* see if it is actually going to resize */
357 x = 0;
358 y = 0;
359 w = cur_w;
360 h = cur_h;
361 client_try_configure(moveresize_client, &x, &y, &w, &h,
362 &lw, &lh, TRUE);
363 if (w == moveresize_client->area.width &&
364 h == moveresize_client->area.height)
366 return;
369 #ifdef SYNC
370 if (config_resize_redraw && extensions_sync &&
371 moveresize_client->sync_request && moveresize_client->sync_counter &&
372 !moveresize_client->not_responding)
374 XEvent ce;
375 XSyncValue val;
377 /* are we already waiting for the sync counter to catch up? */
378 if (waiting_for_sync)
379 return;
381 /* increment the value we're waiting for */
382 ++moveresize_client->sync_counter_value;
383 XSyncIntToValue(&val, moveresize_client->sync_counter_value);
385 /* tell the client what we're waiting for */
386 ce.xclient.type = ClientMessage;
387 ce.xclient.message_type = prop_atoms.wm_protocols;
388 ce.xclient.display = ob_display;
389 ce.xclient.window = moveresize_client->window;
390 ce.xclient.format = 32;
391 ce.xclient.data.l[0] = prop_atoms.net_wm_sync_request;
392 ce.xclient.data.l[1] = event_curtime;
393 ce.xclient.data.l[2] = XSyncValueLow32(val);
394 ce.xclient.data.l[3] = XSyncValueHigh32(val);
395 ce.xclient.data.l[4] = 0l;
396 XSendEvent(ob_display, moveresize_client->window, FALSE,
397 NoEventMask, &ce);
399 waiting_for_sync = TRUE;
401 ob_main_loop_timeout_remove(ob_main_loop, sync_timeout_func);
402 ob_main_loop_timeout_add(ob_main_loop, G_USEC_PER_SEC * 2,
403 sync_timeout_func,
404 NULL, NULL, NULL);
406 #endif
408 client_configure(moveresize_client, cur_x, cur_y, cur_w, cur_h,
409 TRUE, FALSE, FALSE);
411 /* this would be better with a fixed width font ... XXX can do it better
412 if there are 2 text boxes */
413 if (config_resize_popup_show == 2 || /* == "Always" */
414 (config_resize_popup_show == 1 && /* == "Nonpixel" */
415 moveresize_client->size_inc.width > 1 &&
416 moveresize_client->size_inc.height > 1))
417 popup_coords(moveresize_client, "%d x %d",
418 moveresize_client->logical_size.width,
419 moveresize_client->logical_size.height);
422 #ifdef SYNC
423 static gboolean sync_timeout_func(gpointer data)
425 waiting_for_sync = FALSE; /* we timed out waiting for our sync... */
426 do_resize(); /* ...so let any pending resizes through */
428 return FALSE; /* don't repeat */
430 #endif
432 static void calc_resize(gboolean keyboard, gint keydist, gint *dw, gint *dh,
433 ObDirection dir)
435 gint resist, x = 0, y = 0, lw, lh, ow, oh, nw, nh;
436 gint trydw, trydh;
438 ow = cur_w;
439 oh = cur_h;
440 nw = ow + *dw;
441 nh = oh + *dh;
443 if (!keyboard &&
444 (moveresize_client->max_ratio || moveresize_client->min_ratio))
446 switch (dir) {
447 case OB_DIRECTION_NORTH:
448 case OB_DIRECTION_SOUTH:
449 /* resize the width based on the height */
450 if (moveresize_client->min_ratio) {
451 if (nh * moveresize_client->min_ratio > nw)
452 nw = (gint)(nh * moveresize_client->min_ratio);
454 if (moveresize_client->max_ratio) {
455 if (nh * moveresize_client->max_ratio < nw)
456 nw = (gint)(nh * moveresize_client->max_ratio);
458 break;
459 default:
460 /* resize the height based on the width */
461 if (moveresize_client->min_ratio) {
462 if (nh * moveresize_client->min_ratio > nw)
463 nh = (gint)(nw / moveresize_client->min_ratio);
465 if (moveresize_client->max_ratio) {
466 if (nh * moveresize_client->max_ratio < nw)
467 nh = (gint)(nw / moveresize_client->max_ratio);
469 break;
472 /* see its actual size (apply aspect ratios) */
473 client_try_configure(moveresize_client, &x, &y, &nw, &nh, &lw, &lh,
474 TRUE);
475 trydw = nw - ow;
476 trydh = nh - oh;
479 /* resist_size_* needs the frame size */
480 nw += moveresize_client->frame->size.left +
481 moveresize_client->frame->size.right;
482 nh += moveresize_client->frame->size.top +
483 moveresize_client->frame->size.bottom;
485 if (keyboard) resist = keydist - 1; /* resist for one key press */
486 else resist = config_resist_win;
487 resist_size_windows(moveresize_client, resist, &nw, &nh, dir);
488 if (!keyboard) resist = config_resist_edge;
489 resist_size_monitors(moveresize_client, resist, &nw, &nh, dir);
491 nw -= moveresize_client->frame->size.left +
492 moveresize_client->frame->size.right;
493 nh -= moveresize_client->frame->size.top +
494 moveresize_client->frame->size.bottom;
496 *dw = nw - ow;
497 *dh = nh - oh;
499 /* take aspect ratios into account for resistance */
500 if (!keyboard &&
501 (moveresize_client->max_ratio || moveresize_client->min_ratio))
503 if (*dh != trydh) { /* got resisted */
504 /* resize the width based on the height */
505 if (moveresize_client->min_ratio) {
506 if (nh * moveresize_client->min_ratio > nw)
507 nw = (gint)(nh * moveresize_client->min_ratio);
509 if (moveresize_client->max_ratio) {
510 if (nh * moveresize_client->max_ratio < nw)
511 nw = (gint)(nh * moveresize_client->max_ratio);
514 if (*dw != trydw) { /* got resisted */
515 /* resize the height based on the width */
516 if (moveresize_client->min_ratio) {
517 if (nh * moveresize_client->min_ratio > nw)
518 nh = (gint)(nw / moveresize_client->min_ratio);
520 if (moveresize_client->max_ratio) {
521 if (nh * moveresize_client->max_ratio < nw)
522 nh = (gint)(nw / moveresize_client->max_ratio);
527 /* make sure it's all valid */
528 client_try_configure(moveresize_client, &x, &y, &nw, &nh, &lw, &lh, TRUE);
530 *dw = nw - ow;
531 *dh = nh - oh;
534 static gboolean edge_warp_delay_func(gpointer data)
536 guint d;
538 /* only fire every second time. so it's fast the first time, but slower
539 after that */
540 if (edge_warp_odd) {
541 d = screen_find_desktop(screen_desktop, edge_warp_dir, TRUE, FALSE);
542 if (d != screen_desktop) screen_set_desktop(d, TRUE);
544 edge_warp_odd = !edge_warp_odd;
546 return TRUE; /* do repeat ! */
549 static void do_edge_warp(gint x, gint y)
551 guint i;
552 ObDirection dir;
554 if (!config_mouse_screenedgetime) return;
556 dir = -1;
558 for (i = 0; i < screen_num_monitors; ++i) {
559 Rect *a = screen_physical_area_monitor(i);
560 if (x == RECT_LEFT(*a)) dir = OB_DIRECTION_WEST;
561 if (x == RECT_RIGHT(*a)) dir = OB_DIRECTION_EAST;
562 if (y == RECT_TOP(*a)) dir = OB_DIRECTION_NORTH;
563 if (y == RECT_BOTTOM(*a)) dir = OB_DIRECTION_SOUTH;
565 /* try check for xinerama boundaries */
566 if ((x + 1 == RECT_LEFT(*a) || x - 1 == RECT_RIGHT(*a)) &&
567 (dir == OB_DIRECTION_WEST || dir == OB_DIRECTION_EAST))
569 dir = -1;
571 if ((y + 1 == RECT_TOP(*a) || y - 1 == RECT_BOTTOM(*a)) &&
572 (dir == OB_DIRECTION_NORTH || dir == OB_DIRECTION_SOUTH))
574 dir = -1;
576 g_free(a);
579 if (dir != edge_warp_dir) {
580 cancel_edge_warp();
581 if (dir != (ObDirection)-1) {
582 edge_warp_odd = TRUE; /* switch on the first timeout */
583 ob_main_loop_timeout_add(ob_main_loop,
584 config_mouse_screenedgetime * 1000,
585 edge_warp_delay_func,
586 NULL, NULL, NULL);
588 edge_warp_dir = dir;
592 static void cancel_edge_warp(void)
594 ob_main_loop_timeout_remove(ob_main_loop, edge_warp_delay_func);
597 static void move_with_keys(gint keycode, gint state)
599 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
600 gint opx, px, opy, py;
601 gint dist = 0;
603 /* shift means jump to edge */
604 if (state & modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT)) {
605 gint x, y;
606 ObDirection dir;
608 if (keycode == ob_keycode(OB_KEY_RIGHT))
609 dir = OB_DIRECTION_EAST;
610 else if (keycode == ob_keycode(OB_KEY_LEFT))
611 dir = OB_DIRECTION_WEST;
612 else if (keycode == ob_keycode(OB_KEY_DOWN))
613 dir = OB_DIRECTION_SOUTH;
614 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
615 dir = OB_DIRECTION_NORTH;
617 client_find_move_directional(moveresize_client, dir, &x, &y);
618 dx = x - moveresize_client->area.x;
619 dy = y - moveresize_client->area.y;
620 } else {
621 /* control means fine grained */
622 if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL))
623 dist = 1;
624 else
625 dist = KEY_DIST;
627 if (keycode == ob_keycode(OB_KEY_RIGHT))
628 dx = dist;
629 else if (keycode == ob_keycode(OB_KEY_LEFT))
630 dx = -dist;
631 else if (keycode == ob_keycode(OB_KEY_DOWN))
632 dy = dist;
633 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
634 dy = -dist;
637 screen_pointer_pos(&opx, &opy);
638 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
639 /* steal the motion events this causes */
640 XSync(ob_display, FALSE);
642 XEvent ce;
643 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
645 screen_pointer_pos(&px, &py);
647 cur_x += dx;
648 cur_y += dy;
649 do_move(TRUE, dist);
651 /* because the cursor moves even though the window does
652 not nessesarily (resistance), this adjusts where the curor
653 thinks it started so that it keeps up with where the window
654 actually is */
655 start_x += (px - opx) - (cur_x - ox);
656 start_y += (py - opy) - (cur_y - oy);
659 static void resize_with_keys(gint keycode, gint state)
661 gint dw = 0, dh = 0, pdx = 0, pdy = 0, opx, opy, px, py;
662 gint dist = 0, resist = 0;
663 ObDirection dir;
665 /* pick the edge if it needs to move */
666 if (keycode == ob_keycode(OB_KEY_RIGHT)) {
667 dir = OB_DIRECTION_EAST;
668 if (key_resize_edge != OB_DIRECTION_WEST &&
669 key_resize_edge != OB_DIRECTION_EAST)
671 key_resize_edge = OB_DIRECTION_EAST;
672 return;
675 if (keycode == ob_keycode(OB_KEY_LEFT)) {
676 dir = OB_DIRECTION_WEST;
677 if (key_resize_edge != OB_DIRECTION_WEST &&
678 key_resize_edge != OB_DIRECTION_EAST)
680 key_resize_edge = OB_DIRECTION_WEST;
681 return;
684 if (keycode == ob_keycode(OB_KEY_UP)) {
685 dir = OB_DIRECTION_NORTH;
686 if (key_resize_edge != OB_DIRECTION_NORTH &&
687 key_resize_edge != OB_DIRECTION_SOUTH)
689 key_resize_edge = OB_DIRECTION_NORTH;
690 return;
693 if (keycode == ob_keycode(OB_KEY_DOWN)) {
694 dir = OB_DIRECTION_SOUTH;
695 if (key_resize_edge != OB_DIRECTION_NORTH &&
696 key_resize_edge != OB_DIRECTION_SOUTH)
698 key_resize_edge = OB_DIRECTION_SOUTH;
699 return;
703 /* shift means jump to edge */
704 if (state & modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT)) {
705 gint x, y, w, h;
707 if (keycode == ob_keycode(OB_KEY_RIGHT))
708 dir = OB_DIRECTION_EAST;
709 else if (keycode == ob_keycode(OB_KEY_LEFT))
710 dir = OB_DIRECTION_WEST;
711 else if (keycode == ob_keycode(OB_KEY_DOWN))
712 dir = OB_DIRECTION_SOUTH;
713 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
714 dir = OB_DIRECTION_NORTH;
716 client_find_resize_directional(moveresize_client, key_resize_edge,
717 key_resize_edge == dir,
718 &x, &y, &w, &h);
719 dw = w - moveresize_client->area.width;
720 dh = h - moveresize_client->area.height;
721 } else {
722 gint distw, disth;
724 /* control means fine grained */
725 if (moveresize_client->size_inc.width > 1) {
726 distw = moveresize_client->size_inc.width;
727 resist = 1;
729 else if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL)) {
730 distw = 1;
731 resist = 1;
733 else {
734 distw = KEY_DIST;
735 resist = KEY_DIST;
737 if (moveresize_client->size_inc.height > 1) {
738 disth = moveresize_client->size_inc.height;
739 resist = 1;
741 else if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL)) {
742 disth = 1;
743 resist = 1;
745 else {
746 disth = KEY_DIST;
747 resist = KEY_DIST;
750 if (key_resize_edge == OB_DIRECTION_WEST) {
751 if (dir == OB_DIRECTION_WEST)
752 dw = (dist = distw);
753 else
754 dw = -(dist = distw);
756 else if (key_resize_edge == OB_DIRECTION_EAST) {
757 if (dir == OB_DIRECTION_EAST)
758 dw = (dist = distw);
759 else
760 dw = -(dist = distw);
762 else if (key_resize_edge == OB_DIRECTION_NORTH) {
763 if (dir == OB_DIRECTION_NORTH)
764 dh = (dist = disth);
765 else
766 dh = -(dist = disth);
768 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
769 if (dir == OB_DIRECTION_SOUTH)
770 dh = (dist = disth);
771 else
772 dh = -(dist = disth);
776 calc_resize(TRUE, resist, &dw, &dh, dir);
777 if (key_resize_edge == OB_DIRECTION_WEST)
778 cur_x -= dw;
779 else if (key_resize_edge == OB_DIRECTION_NORTH)
780 cur_y -= dh;
781 cur_w += dw;
782 cur_h += dh;
784 /* how to move the pointer to keep up with the change */
785 if (key_resize_edge == OB_DIRECTION_WEST)
786 pdx = -dw;
787 else if (key_resize_edge == OB_DIRECTION_EAST)
788 pdx = dw;
789 else if (key_resize_edge == OB_DIRECTION_NORTH)
790 pdy = -dh;
791 else if (key_resize_edge == OB_DIRECTION_SOUTH)
792 pdy = dh;
794 screen_pointer_pos(&opx, &opy);
795 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, pdx, pdy);
796 /* steal the motion events this causes */
797 XSync(ob_display, FALSE);
799 XEvent ce;
800 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
802 screen_pointer_pos(&px, &py);
804 do_resize();
806 /* because the cursor moves even though the window does
807 not nessesarily (resistance), this adjusts where the cursor
808 thinks it started so that it keeps up with where the window
809 actually is */
810 start_x += (px - opx) - dw;
811 start_y += (py - opy) - dh;
815 gboolean moveresize_event(XEvent *e)
817 gboolean used = FALSE;
819 if (!moveresize_in_progress) return FALSE;
821 if (e->type == ButtonPress) {
822 if (!button) {
823 start_x = e->xbutton.x_root;
824 start_y = e->xbutton.y_root;
825 button = e->xbutton.button; /* this will end it now */
827 used = e->xbutton.button == button;
828 } else if (e->type == ButtonRelease) {
829 if (!button || e->xbutton.button == button) {
830 moveresize_end(FALSE);
831 used = TRUE;
833 } else if (e->type == MotionNotify) {
834 if (moving) {
835 cur_x = start_cx + e->xmotion.x_root - start_x;
836 cur_y = start_cy + e->xmotion.y_root - start_y;
837 do_move(FALSE, 0);
838 do_edge_warp(e->xmotion.x_root, e->xmotion.y_root);
839 } else {
840 gint dw, dh;
841 ObDirection dir;
843 if (corner == prop_atoms.net_wm_moveresize_size_topleft) {
844 dw = -(e->xmotion.x_root - start_x);
845 dh = -(e->xmotion.y_root - start_y);
846 dir = OB_DIRECTION_NORTHWEST;
847 } else if (corner == prop_atoms.net_wm_moveresize_size_top) {
848 dw = 0;
849 dh = -(e->xmotion.y_root - start_y);
850 dir = OB_DIRECTION_NORTH;
851 } else if (corner == prop_atoms.net_wm_moveresize_size_topright) {
852 dw = (e->xmotion.x_root - start_x);
853 dh = -(e->xmotion.y_root - start_y);
854 dir = OB_DIRECTION_NORTHEAST;
855 } else if (corner == prop_atoms.net_wm_moveresize_size_right) {
856 dw = (e->xmotion.x_root - start_x);
857 dh = 0;
858 dir = OB_DIRECTION_EAST;
859 } else if (corner ==
860 prop_atoms.net_wm_moveresize_size_bottomright) {
861 dw = (e->xmotion.x_root - start_x);
862 dh = (e->xmotion.y_root - start_y);
863 dir = OB_DIRECTION_SOUTHEAST;
864 } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) {
865 dw = 0;
866 dh = (e->xmotion.y_root - start_y);
867 dir = OB_DIRECTION_SOUTH;
868 } else if (corner ==
869 prop_atoms.net_wm_moveresize_size_bottomleft) {
870 dw = -(e->xmotion.x_root - start_x);
871 dh = (e->xmotion.y_root - start_y);
872 dir = OB_DIRECTION_SOUTHWEST;
873 } else if (corner == prop_atoms.net_wm_moveresize_size_left) {
874 dw = -(e->xmotion.x_root - start_x);
875 dh = 0;
876 dir = OB_DIRECTION_WEST;
877 } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
878 dw = (e->xmotion.x_root - start_x);
879 dh = (e->xmotion.y_root - start_y);
880 dir = OB_DIRECTION_SOUTHEAST;
881 } else
882 g_assert_not_reached();
884 dw -= cur_w - start_cw;
885 dh -= cur_h - start_ch;
887 calc_resize(FALSE, 0, &dw, &dh, dir);
888 cur_w += dw;
889 cur_h += dh;
891 if (corner == prop_atoms.net_wm_moveresize_size_topleft ||
892 corner == prop_atoms.net_wm_moveresize_size_left ||
893 corner == prop_atoms.net_wm_moveresize_size_bottomleft)
895 cur_x -= dw;
897 if (corner == prop_atoms.net_wm_moveresize_size_topleft ||
898 corner == prop_atoms.net_wm_moveresize_size_top ||
899 corner == prop_atoms.net_wm_moveresize_size_topright)
901 cur_y -= dh;
904 do_resize();
906 used = TRUE;
907 } else if (e->type == KeyPress) {
908 if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
909 moveresize_end(TRUE);
910 used = TRUE;
911 } else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
912 moveresize_end(FALSE);
913 used = TRUE;
914 } else if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT) ||
915 e->xkey.keycode == ob_keycode(OB_KEY_LEFT) ||
916 e->xkey.keycode == ob_keycode(OB_KEY_DOWN) ||
917 e->xkey.keycode == ob_keycode(OB_KEY_UP))
919 if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
920 resize_with_keys(e->xkey.keycode, e->xkey.state);
921 used = TRUE;
922 } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
923 move_with_keys(e->xkey.keycode, e->xkey.state);
924 used = TRUE;
928 #ifdef SYNC
929 else if (e->type == extensions_sync_event_basep + XSyncAlarmNotify)
931 waiting_for_sync = FALSE; /* we got our sync... */
932 do_resize(); /* ...so try resize if there is more change pending */
933 used = TRUE;
935 #endif
936 return used;