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.
21 #include "framerender.h"
29 #include "moveresize.h"
33 #include "obrender/render.h"
34 #include "obrender/theme.h"
35 #include "obt/display.h"
36 #include "obt/xqueue.h"
38 #include "obt/keyboard.h"
43 /* how far windows move and resize with the keyboard arrows */
45 #define SYNC_TIMEOUTS 4
47 gboolean moveresize_in_progress = FALSE;
48 ObClient *moveresize_client = NULL;
50 XSyncAlarm moveresize_alarm = None;
53 static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */
55 /* starting geometry for the window being moved/resized, so it can be
57 static gint start_x, start_y, start_cx, start_cy, start_cw, start_ch;
58 static gboolean was_max_horz, was_max_vert;
59 static Rect pre_max_area;
60 static gint cur_x, cur_y, cur_w, cur_h;
62 static guint32 corner;
63 static ObDirection edge_warp_dir = -1;
64 static gboolean edge_warp_odd = FALSE;
65 static guint edge_warp_timer = 0;
66 static ObDirection key_resize_edge = -1;
67 static guint waiting_for_sync;
69 static guint sync_timer = 0;
72 static ObPopup *popup = NULL;
74 static void do_move(gboolean keyboard, gint keydist);
75 static void do_resize(void);
76 static void do_edge_warp(gint x, gint y);
77 static void cancel_edge_warp();
79 static gboolean sync_timeout_func(gpointer data);
82 static void client_dest(ObClient *client, gpointer data)
84 if (moveresize_client == client)
86 if (popup && client == popup->client)
90 void moveresize_startup(gboolean reconfig)
93 popup_set_text_align(popup, RR_JUSTIFY_CENTER);
96 client_add_destroy_notify(client_dest, NULL);
99 void moveresize_shutdown(gboolean reconfig)
102 if (moveresize_in_progress)
103 moveresize_end(FALSE);
104 client_remove_destroy_notify(client_dest);
111 static void popup_coords(ObClient *c, const gchar *format, gint a, gint b)
115 text = g_strdup_printf(format, a, b);
116 if (config_resize_popup_pos == OB_RESIZE_POS_TOP)
117 popup_position(popup, SouthGravity,
119 + c->frame->area.width/2,
120 c->frame->area.y - ob_rr_theme->fbwidth);
121 else if (config_resize_popup_pos == OB_RESIZE_POS_CENTER)
122 popup_position(popup, CenterGravity,
123 c->frame->area.x + c->frame->area.width / 2,
124 c->frame->area.y + c->frame->area.height / 2);
126 const Rect *area = screen_physical_area_active();
129 x = config_resize_popup_fixed.x.pos;
130 if (config_resize_popup_fixed.x.center)
131 x = area->x + area->width/2;
132 else if (config_resize_popup_fixed.x.opposite)
133 x = RECT_RIGHT(*area) - x;
137 y = config_resize_popup_fixed.y.pos;
138 if (config_resize_popup_fixed.y.center)
139 y = area->y + area->height/2;
140 else if (config_resize_popup_fixed.y.opposite)
141 y = RECT_RIGHT(*area) - y;
145 if (config_resize_popup_fixed.x.center) {
146 if (config_resize_popup_fixed.y.center)
147 gravity = CenterGravity;
148 else if (config_resize_popup_fixed.y.opposite)
149 gravity = SouthGravity;
151 gravity = NorthGravity;
153 else if (config_resize_popup_fixed.x.opposite) {
154 if (config_resize_popup_fixed.y.center)
155 gravity = EastGravity;
156 else if (config_resize_popup_fixed.y.opposite)
157 gravity = SouthEastGravity;
159 gravity = NorthEastGravity;
162 if (config_resize_popup_fixed.y.center)
163 gravity = WestGravity;
164 else if (config_resize_popup_fixed.y.opposite)
165 gravity = SouthWestGravity;
167 gravity = NorthWestGravity;
170 popup_position(popup, gravity, x, y);
173 popup_show(popup, text);
177 void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
180 gboolean mv = (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE) ||
181 cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD));
185 if (moveresize_in_progress || !c->frame->visible ||
187 (c->functions & OB_CLIENT_FUNC_MOVE) :
188 (c->functions & OB_CLIENT_FUNC_RESIZE)))
191 if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT)) {
192 cur = OB_CURSOR_NORTHWEST;
195 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP)) {
196 cur = OB_CURSOR_NORTH;
199 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT)) {
200 cur = OB_CURSOR_NORTHEAST;
203 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT))
204 cur = OB_CURSOR_EAST;
205 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT))
206 cur = OB_CURSOR_SOUTHEAST;
207 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM))
208 cur = OB_CURSOR_SOUTH;
209 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT)) {
210 cur = OB_CURSOR_SOUTHWEST;
213 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT)) {
214 cur = OB_CURSOR_WEST;
217 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD))
218 cur = OB_CURSOR_SOUTHEAST;
219 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE))
220 cur = OB_CURSOR_MOVE;
221 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD))
222 cur = OB_CURSOR_MOVE;
224 g_assert_not_reached();
226 /* keep the pointer bounded to the screen for move/resize */
227 if (!grab_pointer(FALSE, TRUE, cur))
229 if (!grab_keyboard()) {
234 frame_end_iconify_animation(c->frame);
237 moveresize_client = c;
238 start_cx = c->area.x;
239 start_cy = c->area.y;
240 start_cw = c->area.width;
241 start_ch = c->area.height;
242 /* these adjustments for the size_inc make resizing a terminal more
243 friendly. you essentially start the resize in the middle of the
244 increment instead of at 0, so you have to move half an increment
245 either way instead of a full increment one and 1 px the other. */
246 start_x = x - (mv ? 0 : left * c->size_inc.width / 2);
247 start_y = y - (mv ? 0 : up * c->size_inc.height / 2);
250 key_resize_edge = -1;
252 /* default to not putting max back on cancel */
253 was_max_horz = was_max_vert = FALSE;
256 have to change start_cx and start_cy if going to do this..
257 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
258 corner == prop_atoms.net_wm_moveresize_size_keyboard)
259 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
260 c->area.width / 2, c->area.height / 2);
268 moveresize_in_progress = TRUE;
269 waiting_for_sync = 0;
277 if (config_resize_redraw && !moving && obt_display_extension_sync &&
278 moveresize_client->sync_request && moveresize_client->sync_counter &&
279 !moveresize_client->not_responding)
281 /* Initialize values for the resize syncing, and create an alarm for
282 the client's xsync counter */
285 XSyncAlarmAttributes aa;
287 /* set the counter to an initial value */
288 XSyncIntToValue(&val, 0);
289 XSyncSetCounter(obt_display, moveresize_client->sync_counter, val);
291 /* this will be incremented when we tell the client what we're
293 moveresize_client->sync_counter_value = 0;
295 /* the next sequence we're waiting for with the alarm */
296 XSyncIntToValue(&val, 1);
298 /* set an alarm on the counter */
299 aa.trigger.counter = moveresize_client->sync_counter;
300 aa.trigger.wait_value = val;
301 aa.trigger.value_type = XSyncAbsolute;
302 aa.trigger.test_type = XSyncPositiveTransition;
304 XSyncIntToValue(&aa.delta, 1);
305 moveresize_alarm = XSyncCreateAlarm(obt_display,
317 void moveresize_end(gboolean cancel)
323 popup->client = NULL;
327 /* turn off the alarm */
328 if (moveresize_alarm != None) {
329 XSyncDestroyAlarm(obt_display, moveresize_alarm);
330 moveresize_alarm = None;
333 if (sync_timer) g_source_remove(sync_timer);
338 /* don't use client_move() here, use the same width/height as
339 we've been using during the move, otherwise we get different results
340 when moving maximized windows between monitors of different sizes !
342 client_configure(moveresize_client,
343 (cancel ? start_cx : cur_x),
344 (cancel ? start_cy : cur_y),
345 (cancel ? start_cw : cur_w),
346 (cancel ? start_ch : cur_h),
349 /* restore the client's maximized state. do this after putting the window
350 back in its original spot to minimize visible flicker */
351 if (cancel && (was_max_horz || was_max_vert)) {
352 const gboolean h = moveresize_client->max_horz;
353 const gboolean v = moveresize_client->max_vert;
355 client_maximize(moveresize_client, TRUE,
356 was_max_horz && was_max_vert ? 0 :
357 (was_max_horz ? 1 : 2));
359 /* replace the premax values with the ones we had saved if
360 the client doesn't have any already set */
361 if (was_max_horz && !h) {
362 moveresize_client->pre_max_area.x = pre_max_area.x;
363 moveresize_client->pre_max_area.width = pre_max_area.width;
365 if (was_max_vert && !v) {
366 moveresize_client->pre_max_area.y = pre_max_area.y;
367 moveresize_client->pre_max_area.height = pre_max_area.height;
371 /* dont edge warp after its ended */
374 moveresize_in_progress = FALSE;
375 moveresize_client = NULL;
378 static void do_move(gboolean keyboard, gint keydist)
382 if (keyboard) resist = keydist - 1; /* resist for one key press */
383 else resist = config_resist_win;
384 resist_move_windows(moveresize_client, resist, &cur_x, &cur_y);
385 if (!keyboard) resist = config_resist_edge;
386 resist_move_monitors(moveresize_client, resist, &cur_x, &cur_y);
388 client_configure(moveresize_client, cur_x, cur_y, cur_w, cur_h,
390 if (config_resize_popup_show == 2) /* == "Always" */
391 popup_coords(moveresize_client, "%d x %d",
392 moveresize_client->frame->area.x,
393 moveresize_client->frame->area.y);
396 static void do_resize(void)
398 gint x, y, w, h, lw, lh;
400 /* see if it is actually going to resize
401 USE cur_x AND cur_y HERE ! Otherwise the try_configure won't know
402 what struts to use !!
408 client_try_configure(moveresize_client, &x, &y, &w, &h,
410 if (!(w == moveresize_client->area.width &&
411 h == moveresize_client->area.height) &&
412 /* if waiting_for_sync == 0, then we aren't waiting.
413 if it is > SYNC_TIMEOUTS, then we have timed out
414 that many times already, so forget about waiting more */
415 (waiting_for_sync == 0 || waiting_for_sync > SYNC_TIMEOUTS))
418 if (config_resize_redraw && obt_display_extension_sync &&
419 /* don't send another sync when one is pending */
420 waiting_for_sync == 0 &&
421 moveresize_client->sync_request &&
422 moveresize_client->sync_counter &&
423 !moveresize_client->not_responding)
428 /* increment the value we're waiting for */
429 ++moveresize_client->sync_counter_value;
430 XSyncIntToValue(&val, moveresize_client->sync_counter_value);
432 /* tell the client what we're waiting for */
433 ce.xclient.type = ClientMessage;
434 ce.xclient.message_type = OBT_PROP_ATOM(WM_PROTOCOLS);
435 ce.xclient.display = obt_display;
436 ce.xclient.window = moveresize_client->window;
437 ce.xclient.format = 32;
438 ce.xclient.data.l[0] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST);
439 ce.xclient.data.l[1] = event_time();
440 ce.xclient.data.l[2] = XSyncValueLow32(val);
441 ce.xclient.data.l[3] = XSyncValueHigh32(val);
442 ce.xclient.data.l[4] = 0l;
443 XSendEvent(obt_display, moveresize_client->window, FALSE,
446 waiting_for_sync = 1;
448 if (sync_timer) g_source_remove(sync_timer);
449 sync_timer = g_timeout_add(2000, sync_timeout_func, NULL);
453 /* force a ConfigureNotify, it is part of the spec for SYNC resizing
454 and MUST follow the sync counter notification */
455 client_configure(moveresize_client, cur_x, cur_y, cur_w, cur_h,
459 /* this would be better with a fixed width font ... XXX can do it better
460 if there are 2 text boxes */
461 if (config_resize_popup_show == 2 || /* == "Always" */
462 (config_resize_popup_show == 1 && /* == "Nonpixel" */
463 moveresize_client->size_inc.width > 1 &&
464 moveresize_client->size_inc.height > 1))
465 popup_coords(moveresize_client, "%d x %d", lw, lh);
469 static gboolean sync_timeout_func(gpointer data)
471 ++waiting_for_sync; /* we timed out waiting for our sync... */
472 do_resize(); /* ...so let any pending resizes through */
474 if (waiting_for_sync > SYNC_TIMEOUTS) {
476 return FALSE; /* don't repeat */
479 return TRUE; /* keep waiting */
483 static void calc_resize(gboolean keyboard, gint keydist, gint *dw, gint *dh,
486 gint resist, x = 0, y = 0, lw, lh, ow, oh, nw, nh;
495 (moveresize_client->max_ratio || moveresize_client->min_ratio))
498 case OB_DIRECTION_NORTH:
499 case OB_DIRECTION_SOUTH:
500 /* resize the width based on the height */
501 if (moveresize_client->min_ratio) {
502 if (nh * moveresize_client->min_ratio > nw)
503 nw = (gint)(nh * moveresize_client->min_ratio);
505 if (moveresize_client->max_ratio) {
506 if (nh * moveresize_client->max_ratio < nw)
507 nw = (gint)(nh * moveresize_client->max_ratio);
511 /* resize the height based on the width */
512 if (moveresize_client->min_ratio) {
513 if (nh * moveresize_client->min_ratio > nw)
514 nh = (gint)(nw / moveresize_client->min_ratio);
516 if (moveresize_client->max_ratio) {
517 if (nh * moveresize_client->max_ratio < nw)
518 nh = (gint)(nw / moveresize_client->max_ratio);
523 /* see its actual size (apply aspect ratios) */
524 client_try_configure(moveresize_client, &x, &y, &nw, &nh, &lw, &lh,
530 /* resist_size_* needs the frame size */
531 nw += moveresize_client->frame->size.left +
532 moveresize_client->frame->size.right;
533 nh += moveresize_client->frame->size.top +
534 moveresize_client->frame->size.bottom;
536 if (keyboard) resist = keydist - 1; /* resist for one key press */
537 else resist = config_resist_win;
538 resist_size_windows(moveresize_client, resist, &nw, &nh, dir);
539 if (!keyboard) resist = config_resist_edge;
540 resist_size_monitors(moveresize_client, resist, &nw, &nh, dir);
542 nw -= moveresize_client->frame->size.left +
543 moveresize_client->frame->size.right;
544 nh -= moveresize_client->frame->size.top +
545 moveresize_client->frame->size.bottom;
550 /* take aspect ratios into account for resistance */
552 (moveresize_client->max_ratio || moveresize_client->min_ratio))
554 if (*dh != trydh) { /* got resisted */
555 /* resize the width based on the height */
556 if (moveresize_client->min_ratio) {
557 if (nh * moveresize_client->min_ratio > nw)
558 nw = (gint)(nh * moveresize_client->min_ratio);
560 if (moveresize_client->max_ratio) {
561 if (nh * moveresize_client->max_ratio < nw)
562 nw = (gint)(nh * moveresize_client->max_ratio);
565 if (*dw != trydw) { /* got resisted */
566 /* resize the height based on the width */
567 if (moveresize_client->min_ratio) {
568 if (nh * moveresize_client->min_ratio > nw)
569 nh = (gint)(nw / moveresize_client->min_ratio);
571 if (moveresize_client->max_ratio) {
572 if (nh * moveresize_client->max_ratio < nw)
573 nh = (gint)(nw / moveresize_client->max_ratio);
578 /* make sure it's all valid */
579 client_try_configure(moveresize_client, &x, &y, &nw, &nh, &lw, &lh, TRUE);
585 static void edge_warp_move_ptr(void)
590 screen_pointer_pos(&x, &y);
591 a = screen_physical_area_all_monitors();
593 switch (edge_warp_dir) {
594 case OB_DIRECTION_NORTH:
597 case OB_DIRECTION_EAST:
600 case OB_DIRECTION_SOUTH:
603 case OB_DIRECTION_WEST:
607 g_assert_not_reached();
610 XWarpPointer(obt_display, 0, obt_root(ob_screen), 0, 0, 0, 0, x, y);
613 static gboolean edge_warp_delay_func(gpointer data)
617 /* only fire every second time. so it's fast the first time, but slower
620 d = screen_find_desktop(screen_desktop, edge_warp_dir, TRUE, FALSE);
621 if (d != screen_desktop) {
622 if (config_mouse_screenedgewarp) edge_warp_move_ptr();
623 screen_set_desktop(d, TRUE);
626 edge_warp_odd = !edge_warp_odd;
628 return TRUE; /* do repeat ! */
631 static void do_edge_warp(gint x, gint y)
636 if (!config_mouse_screenedgetime) return;
640 for (i = 0; i < screen_num_monitors; ++i) {
641 const Rect *a = screen_physical_area_monitor(i);
643 if (!RECT_CONTAINS(*a, x, y))
646 if (x == RECT_LEFT(*a)) dir = OB_DIRECTION_WEST;
647 if (x == RECT_RIGHT(*a)) dir = OB_DIRECTION_EAST;
648 if (y == RECT_TOP(*a)) dir = OB_DIRECTION_NORTH;
649 if (y == RECT_BOTTOM(*a)) dir = OB_DIRECTION_SOUTH;
651 /* try check for xinerama boundaries */
652 if ((x + 1 == RECT_LEFT(*a) || x - 1 == RECT_RIGHT(*a)) &&
653 (dir == OB_DIRECTION_WEST || dir == OB_DIRECTION_EAST))
657 if ((y + 1 == RECT_TOP(*a) || y - 1 == RECT_BOTTOM(*a)) &&
658 (dir == OB_DIRECTION_NORTH || dir == OB_DIRECTION_SOUTH))
664 if (dir != edge_warp_dir) {
666 if (dir != (ObDirection)-1) {
667 edge_warp_odd = TRUE; /* switch on the first timeout */
668 edge_warp_timer = g_timeout_add(config_mouse_screenedgetime,
669 edge_warp_delay_func, NULL);
675 static void cancel_edge_warp(void)
677 if (edge_warp_timer) g_source_remove(edge_warp_timer);
681 static void move_with_keys(KeySym sym, guint state)
683 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
684 gint opx, px, opy, py;
687 /* shift means jump to edge */
688 if (state & obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT))
694 dir = OB_DIRECTION_EAST;
695 else if (sym == XK_Left)
696 dir = OB_DIRECTION_WEST;
697 else if (sym == XK_Down)
698 dir = OB_DIRECTION_SOUTH;
699 else /* sym == XK_Up */
700 dir = OB_DIRECTION_NORTH;
702 client_find_move_directional(moveresize_client, dir, &x, &y);
703 dx = x - moveresize_client->area.x;
704 dy = y - moveresize_client->area.y;
706 /* control means fine grained */
708 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL))
717 else if (sym == XK_Left)
719 else if (sym == XK_Down)
721 else /* if (sym == XK_Up) */
725 screen_pointer_pos(&opx, &opy);
726 XWarpPointer(obt_display, None, None, 0, 0, 0, 0, dx, dy);
727 /* steal the motion events this causes */
728 XSync(obt_display, FALSE);
731 while (xqueue_remove_local(&ce, xqueue_match_type,
732 GINT_TO_POINTER(MotionNotify)));
734 screen_pointer_pos(&px, &py);
740 /* because the cursor moves even though the window does
741 not nessesarily (resistance), this adjusts where the curor
742 thinks it started so that it keeps up with where the window
744 start_x += (px - opx) - (cur_x - ox);
745 start_y += (py - opy) - (cur_y - oy);
748 static void resize_with_keys(KeySym sym, guint state)
750 gint dw = 0, dh = 0, pdx = 0, pdy = 0, opx, opy, px, py;
754 /* pick the edge if it needs to move */
755 if (sym == XK_Right) {
756 dir = OB_DIRECTION_EAST;
757 if (key_resize_edge != OB_DIRECTION_WEST &&
758 key_resize_edge != OB_DIRECTION_EAST)
760 key_resize_edge = OB_DIRECTION_EAST;
763 } else if (sym == XK_Left) {
764 dir = OB_DIRECTION_WEST;
765 if (key_resize_edge != OB_DIRECTION_WEST &&
766 key_resize_edge != OB_DIRECTION_EAST)
768 key_resize_edge = OB_DIRECTION_WEST;
771 } else if (sym == XK_Up) {
772 dir = OB_DIRECTION_NORTH;
773 if (key_resize_edge != OB_DIRECTION_NORTH &&
774 key_resize_edge != OB_DIRECTION_SOUTH)
776 key_resize_edge = OB_DIRECTION_NORTH;
779 } else /* if (sym == XK_Down) */ {
780 dir = OB_DIRECTION_SOUTH;
781 if (key_resize_edge != OB_DIRECTION_NORTH &&
782 key_resize_edge != OB_DIRECTION_SOUTH)
784 key_resize_edge = OB_DIRECTION_SOUTH;
789 /* shift means jump to edge */
790 if (state & obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT))
795 dir = OB_DIRECTION_EAST;
796 else if (sym == XK_Left)
797 dir = OB_DIRECTION_WEST;
798 else if (sym == XK_Down)
799 dir = OB_DIRECTION_SOUTH;
800 else /* if (sym == XK_Up)) */
801 dir = OB_DIRECTION_NORTH;
803 ObClientDirectionalResizeType resize_type =
804 key_resize_edge == dir ? CLIENT_RESIZE_GROW
805 : CLIENT_RESIZE_SHRINK;
807 client_find_resize_directional(moveresize_client,
811 dw = w - moveresize_client->area.width;
812 dh = h - moveresize_client->area.height;
816 /* control means fine grained */
817 if (moveresize_client->size_inc.width > 1) {
818 distw = moveresize_client->size_inc.width;
822 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL))
831 if (moveresize_client->size_inc.height > 1) {
832 disth = moveresize_client->size_inc.height;
836 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL))
846 if (key_resize_edge == OB_DIRECTION_WEST) {
847 if (dir == OB_DIRECTION_WEST)
852 else if (key_resize_edge == OB_DIRECTION_EAST) {
853 if (dir == OB_DIRECTION_EAST)
858 else if (key_resize_edge == OB_DIRECTION_NORTH) {
859 if (dir == OB_DIRECTION_NORTH)
864 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
865 if (dir == OB_DIRECTION_SOUTH)
872 if (moveresize_client->max_horz &&
873 (key_resize_edge == OB_DIRECTION_WEST ||
874 key_resize_edge == OB_DIRECTION_EAST))
878 pre_max_area.x = moveresize_client->pre_max_area.x;
879 pre_max_area.width = moveresize_client->pre_max_area.width;
881 moveresize_client->pre_max_area.x = cur_x;
882 moveresize_client->pre_max_area.width = cur_w;
883 client_maximize(moveresize_client, FALSE, 1);
885 else if (moveresize_client->max_vert &&
886 (key_resize_edge == OB_DIRECTION_NORTH ||
887 key_resize_edge == OB_DIRECTION_SOUTH))
891 pre_max_area.y = moveresize_client->pre_max_area.y;
892 pre_max_area.height = moveresize_client->pre_max_area.height;
894 moveresize_client->pre_max_area.y = cur_y;
895 moveresize_client->pre_max_area.height = cur_h;
896 client_maximize(moveresize_client, FALSE, 2);
899 calc_resize(TRUE, resist, &dw, &dh, dir);
900 if (key_resize_edge == OB_DIRECTION_WEST)
902 else if (key_resize_edge == OB_DIRECTION_NORTH)
907 /* how to move the pointer to keep up with the change */
908 if (key_resize_edge == OB_DIRECTION_WEST)
910 else if (key_resize_edge == OB_DIRECTION_EAST)
912 else if (key_resize_edge == OB_DIRECTION_NORTH)
914 else if (key_resize_edge == OB_DIRECTION_SOUTH)
917 screen_pointer_pos(&opx, &opy);
918 XWarpPointer(obt_display, None, None, 0, 0, 0, 0, pdx, pdy);
919 /* steal the motion events this causes */
920 XSync(obt_display, FALSE);
923 while (xqueue_remove_local(&ce, xqueue_match_type,
924 GINT_TO_POINTER(MotionNotify)));
926 screen_pointer_pos(&px, &py);
930 /* because the cursor moves even though the window does
931 not nessesarily (resistance), this adjusts where the cursor
932 thinks it started so that it keeps up with where the window
934 start_x += (px - opx) - dw;
935 start_y += (py - opy) - dh;
939 gboolean moveresize_event(XEvent *e)
941 gboolean used = FALSE;
943 if (!moveresize_in_progress) return FALSE;
945 if (e->type == ButtonPress) {
947 start_x = e->xbutton.x_root;
948 start_y = e->xbutton.y_root;
949 button = e->xbutton.button; /* this will end it now */
951 used = e->xbutton.button == button;
952 } else if (e->type == ButtonRelease) {
953 if (!button || e->xbutton.button == button) {
954 moveresize_end(FALSE);
957 } else if (e->type == MotionNotify) {
959 cur_x = start_cx + e->xmotion.x_root - start_x;
960 cur_y = start_cy + e->xmotion.y_root - start_y;
962 do_edge_warp(e->xmotion.x_root, e->xmotion.y_root);
967 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT)) {
968 dw = -(e->xmotion.x_root - start_x);
969 dh = -(e->xmotion.y_root - start_y);
970 dir = OB_DIRECTION_NORTHWEST;
971 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP)) {
973 dh = -(e->xmotion.y_root - start_y);
974 dir = OB_DIRECTION_NORTH;
976 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT)) {
977 dw = (e->xmotion.x_root - start_x);
978 dh = -(e->xmotion.y_root - start_y);
979 dir = OB_DIRECTION_NORTHEAST;
980 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT)) {
981 dw = (e->xmotion.x_root - start_x);
983 dir = OB_DIRECTION_EAST;
985 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT)) {
986 dw = (e->xmotion.x_root - start_x);
987 dh = (e->xmotion.y_root - start_y);
988 dir = OB_DIRECTION_SOUTHEAST;
989 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM))
992 dh = (e->xmotion.y_root - start_y);
993 dir = OB_DIRECTION_SOUTH;
995 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT)) {
996 dw = -(e->xmotion.x_root - start_x);
997 dh = (e->xmotion.y_root - start_y);
998 dir = OB_DIRECTION_SOUTHWEST;
999 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT)) {
1000 dw = -(e->xmotion.x_root - start_x);
1002 dir = OB_DIRECTION_WEST;
1003 } else if (corner ==
1004 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD)) {
1005 dw = (e->xmotion.x_root - start_x);
1006 dh = (e->xmotion.y_root - start_y);
1007 dir = OB_DIRECTION_SOUTHEAST;
1009 g_assert_not_reached();
1011 /* override the client's max state if desired */
1012 if (ABS(dw) >= config_resist_edge) {
1013 if (moveresize_client->max_horz) {
1015 was_max_horz = TRUE;
1016 pre_max_area.x = moveresize_client->pre_max_area.x;
1017 pre_max_area.width = moveresize_client->pre_max_area.width;
1019 moveresize_client->pre_max_area.x = cur_x;
1020 moveresize_client->pre_max_area.width = cur_w;
1021 client_maximize(moveresize_client, FALSE, 1);
1024 else if (was_max_horz && !moveresize_client->max_horz) {
1025 /* remax horz and put the premax back */
1026 client_maximize(moveresize_client, TRUE, 1);
1027 moveresize_client->pre_max_area.x = pre_max_area.x;
1028 moveresize_client->pre_max_area.width = pre_max_area.width;
1031 if (ABS(dh) >= config_resist_edge) {
1032 if (moveresize_client->max_vert) {
1034 was_max_vert = TRUE;
1035 pre_max_area.y = moveresize_client->pre_max_area.y;
1036 pre_max_area.height =
1037 moveresize_client->pre_max_area.height;
1039 moveresize_client->pre_max_area.y = cur_y;
1040 moveresize_client->pre_max_area.height = cur_h;
1041 client_maximize(moveresize_client, FALSE, 2);
1044 else if (was_max_vert && !moveresize_client->max_vert) {
1045 /* remax vert and put the premax back */
1046 client_maximize(moveresize_client, TRUE, 2);
1047 moveresize_client->pre_max_area.y = pre_max_area.y;
1048 moveresize_client->pre_max_area.height = pre_max_area.height;
1051 dw -= cur_w - start_cw;
1052 dh -= cur_h - start_ch;
1054 calc_resize(FALSE, 0, &dw, &dh, dir);
1058 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT) ||
1059 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT) ||
1060 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT))
1064 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT) ||
1065 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP) ||
1066 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT))
1074 } else if (e->type == KeyPress) {
1075 KeySym sym = obt_keyboard_keypress_to_keysym(e);
1077 if (sym == XK_Escape) {
1078 moveresize_end(TRUE);
1080 } else if (sym == XK_Return || sym == XK_KP_Enter) {
1081 moveresize_end(FALSE);
1083 } else if (sym == XK_Right || sym == XK_Left ||
1084 sym == XK_Up || sym == XK_Down)
1086 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD)) {
1087 resize_with_keys(sym, e->xkey.state);
1089 } else if (corner ==
1090 OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD))
1092 move_with_keys(sym, e->xkey.state);
1098 else if (e->type == obt_display_extension_sync_basep + XSyncAlarmNotify)
1100 waiting_for_sync = 0; /* we got our sync... */
1101 do_resize(); /* ...so try resize if there is more change pending */
1106 if (used && moveresize_client == focus_client)
1107 event_update_user_time();