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"
31 #include "moveresize.h"
35 #include "extensions.h"
36 #include "render/render.h"
37 #include "render/theme.h"
42 /* how far windows move and resize with the keyboard arrows */
45 gboolean moveresize_in_progress
= FALSE
;
46 ObClient
*moveresize_client
= NULL
;
48 XSyncAlarm moveresize_alarm
= None
;
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
;
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;
61 static gboolean waiting_for_sync
;
64 static ObPopup
*popup
= NULL
;
66 static void do_edge_warp(gint x
, gint y
);
67 static void cancel_edge_warp();
69 static gboolean
sync_timeout_func(gpointer data
);
72 static void client_dest(ObClient
*client
, gpointer data
)
74 if (moveresize_client
== client
)
78 void moveresize_startup(gboolean reconfig
)
81 popup_set_text_align(popup
, RR_JUSTIFY_CENTER
);
84 client_add_destroy_notify(client_dest
, NULL
);
87 void moveresize_shutdown(gboolean reconfig
)
90 if (moveresize_in_progress
)
91 moveresize_end(FALSE
);
92 client_remove_destroy_notify(client_dest
);
99 static void popup_coords(ObClient
*c
, const gchar
*format
, gint a
, gint b
)
103 text
= g_strdup_printf(format
, a
, b
);
104 if (config_resize_popup_pos
== OB_RESIZE_POS_TOP
)
105 popup_position(popup
, SouthGravity
,
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
+
113 c
->frame
->area
.y
+ c
->frame
->size
.top
+
116 Rect
*area
= screen_physical_area_active();
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
;
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
;
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
;
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
;
149 gravity
= NorthEastGravity
;
152 if (config_resize_popup_fixed
.y
.center
)
153 gravity
= WestGravity
;
154 else if (config_resize_popup_fixed
.y
.opposite
)
155 gravity
= SouthWestGravity
;
157 gravity
= NorthWestGravity
;
160 popup_position(popup
, gravity
, x
, y
);
164 popup_show(popup
, text
);
168 void moveresize_start(ObClient
*c
, gint x
, gint y
, guint b
, guint32 cnr
)
171 gboolean mv
= (cnr
== prop_atoms
.net_wm_moveresize_move
||
172 cnr
== prop_atoms
.net_wm_moveresize_move_keyboard
);
176 if (moveresize_in_progress
|| !c
->frame
->visible
||
178 (c
->functions
& OB_CLIENT_FUNC_MOVE
) :
179 (c
->functions
& OB_CLIENT_FUNC_RESIZE
)))
182 if (cnr
== prop_atoms
.net_wm_moveresize_size_topleft
) {
183 cur
= OB_CURSOR_NORTHWEST
;
185 } else if (cnr
== prop_atoms
.net_wm_moveresize_size_top
) {
186 cur
= OB_CURSOR_NORTH
;
188 } else if (cnr
== prop_atoms
.net_wm_moveresize_size_topright
) {
189 cur
= OB_CURSOR_NORTHEAST
;
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
;
200 } else if (cnr
== prop_atoms
.net_wm_moveresize_size_left
) {
201 cur
= OB_CURSOR_WEST
;
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
;
210 g_assert_not_reached();
212 /* keep the pointer bounded to the screen for move/resize */
213 if (!grab_pointer(FALSE
, TRUE
, cur
))
215 if (!grab_keyboard()) {
220 frame_end_iconify_animation(c
->frame
);
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);
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);
251 moveresize_in_progress
= TRUE
;
254 if (config_resize_redraw
&& !moving
&& extensions_sync
&&
255 moveresize_client
->sync_request
&& moveresize_client
->sync_counter
)
257 /* Initialize values for the resize syncing, and create an alarm for
258 the client's xsync counter */
261 XSyncAlarmAttributes aa
;
263 /* set the counter to an initial value */
264 XSyncIntToValue(&val
, 0);
265 XSyncSetCounter(ob_display
, moveresize_client
->sync_counter
, val
);
267 /* this will be incremented when we tell the client what we're
269 moveresize_client
->sync_counter_value
= 0;
271 /* the next sequence we're waiting for with the alarm */
272 XSyncIntToValue(&val
, 1);
274 /* set an alarm on the counter */
275 aa
.trigger
.counter
= moveresize_client
->sync_counter
;
276 aa
.trigger
.wait_value
= val
;
277 aa
.trigger
.value_type
= XSyncAbsolute
;
278 aa
.trigger
.test_type
= XSyncPositiveTransition
;
280 XSyncIntToValue(&aa
.delta
, 1);
281 moveresize_alarm
= XSyncCreateAlarm(ob_display
,
290 waiting_for_sync
= FALSE
;
295 void moveresize_end(gboolean cancel
)
303 client_move(moveresize_client
,
304 (cancel
? start_cx
: cur_x
),
305 (cancel
? start_cy
: cur_y
));
308 /* turn off the alarm */
309 if (moveresize_alarm
!= None
) {
310 XSyncDestroyAlarm(ob_display
, moveresize_alarm
);
311 moveresize_alarm
= None
;
314 ob_main_loop_timeout_remove(ob_main_loop
, sync_timeout_func
);
317 client_configure(moveresize_client
,
318 (cancel
? start_cx
: cur_x
),
319 (cancel
? start_cy
: cur_y
),
320 (cancel
? start_cw
: cur_w
),
321 (cancel
? start_ch
: cur_h
),
325 /* dont edge warp after its ended */
328 moveresize_in_progress
= FALSE
;
329 moveresize_client
= NULL
;
332 static void do_move(gboolean keyboard
, gint keydist
)
336 if (keyboard
) resist
= keydist
- 1; /* resist for one key press */
337 else resist
= config_resist_win
;
338 resist_move_windows(moveresize_client
, resist
, &cur_x
, &cur_y
);
339 if (!keyboard
) resist
= config_resist_edge
;
340 resist_move_monitors(moveresize_client
, resist
, &cur_x
, &cur_y
);
342 client_configure(moveresize_client
, cur_x
, cur_y
, cur_w
, cur_h
,
344 if (config_resize_popup_show
== 2) /* == "Always" */
345 popup_coords(moveresize_client
, "%d x %d",
346 moveresize_client
->frame
->area
.x
,
347 moveresize_client
->frame
->area
.y
);
351 static void do_resize(void)
353 gint x
, y
, w
, h
, lw
, lh
;
355 /* see if it is actually going to resize */
360 client_try_configure(moveresize_client
, &x
, &y
, &w
, &h
,
362 if (w
== moveresize_client
->area
.width
&&
363 h
== moveresize_client
->area
.height
)
369 if (config_resize_redraw
&& extensions_sync
&&
370 moveresize_client
->sync_request
&& moveresize_client
->sync_counter
)
375 /* are we already waiting for the sync counter to catch up? */
376 if (waiting_for_sync
)
379 /* increment the value we're waiting for */
380 ++moveresize_client
->sync_counter_value
;
381 XSyncIntToValue(&val
, moveresize_client
->sync_counter_value
);
383 /* tell the client what we're waiting for */
384 ce
.xclient
.type
= ClientMessage
;
385 ce
.xclient
.message_type
= prop_atoms
.wm_protocols
;
386 ce
.xclient
.display
= ob_display
;
387 ce
.xclient
.window
= moveresize_client
->window
;
388 ce
.xclient
.format
= 32;
389 ce
.xclient
.data
.l
[0] = prop_atoms
.net_wm_sync_request
;
390 ce
.xclient
.data
.l
[1] = event_curtime
;
391 ce
.xclient
.data
.l
[2] = XSyncValueLow32(val
);
392 ce
.xclient
.data
.l
[3] = XSyncValueHigh32(val
);
393 ce
.xclient
.data
.l
[4] = 0l;
394 XSendEvent(ob_display
, moveresize_client
->window
, FALSE
,
397 waiting_for_sync
= TRUE
;
399 ob_main_loop_timeout_remove(ob_main_loop
, sync_timeout_func
);
400 ob_main_loop_timeout_add(ob_main_loop
, G_USEC_PER_SEC
* 2,
406 client_configure(moveresize_client
, cur_x
, cur_y
, cur_w
, cur_h
,
409 /* this would be better with a fixed width font ... XXX can do it better
410 if there are 2 text boxes */
411 if (config_resize_popup_show
== 2 || /* == "Always" */
412 (config_resize_popup_show
== 1 && /* == "Nonpixel" */
413 moveresize_client
->size_inc
.width
> 1 &&
414 moveresize_client
->size_inc
.height
> 1))
415 popup_coords(moveresize_client
, "%d x %d",
416 moveresize_client
->logical_size
.width
,
417 moveresize_client
->logical_size
.height
);
421 static gboolean
sync_timeout_func(gpointer data
)
423 waiting_for_sync
= FALSE
; /* we timed out waiting for our sync... */
424 do_resize(); /* ...so let any pending resizes through */
426 return FALSE
; /* don't repeat */
430 static void calc_resize(gboolean keyboard
, gint keydist
, gint
*dw
, gint
*dh
,
433 gint resist
, x
= 0, y
= 0, lw
, lh
, ow
, oh
, nw
, nh
;
442 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
445 case OB_DIRECTION_NORTH
:
446 case OB_DIRECTION_SOUTH
:
447 /* resize the width based on the height */
448 if (moveresize_client
->min_ratio
) {
449 if (nh
* moveresize_client
->min_ratio
> nw
)
450 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
452 if (moveresize_client
->max_ratio
) {
453 if (nh
* moveresize_client
->max_ratio
< nw
)
454 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
458 /* resize the height based on the width */
459 if (moveresize_client
->min_ratio
) {
460 if (nh
* moveresize_client
->min_ratio
> nw
)
461 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
463 if (moveresize_client
->max_ratio
) {
464 if (nh
* moveresize_client
->max_ratio
< nw
)
465 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
470 /* see its actual size (apply aspect ratios) */
471 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
,
477 /* resist_size_* needs the frame size */
478 nw
+= moveresize_client
->frame
->size
.left
+
479 moveresize_client
->frame
->size
.right
;
480 nh
+= moveresize_client
->frame
->size
.top
+
481 moveresize_client
->frame
->size
.bottom
;
483 if (keyboard
) resist
= keydist
- 1; /* resist for one key press */
484 else resist
= config_resist_win
;
485 resist_size_windows(moveresize_client
, resist
, &nw
, &nh
, dir
);
486 if (!keyboard
) resist
= config_resist_edge
;
487 resist_size_monitors(moveresize_client
, resist
, &nw
, &nh
, dir
);
489 nw
-= moveresize_client
->frame
->size
.left
+
490 moveresize_client
->frame
->size
.right
;
491 nh
-= moveresize_client
->frame
->size
.top
+
492 moveresize_client
->frame
->size
.bottom
;
497 /* take aspect ratios into account for resistance */
499 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
501 if (*dh
!= trydh
) { /* got resisted */
502 /* resize the width based on the height */
503 if (moveresize_client
->min_ratio
) {
504 if (nh
* moveresize_client
->min_ratio
> nw
)
505 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
507 if (moveresize_client
->max_ratio
) {
508 if (nh
* moveresize_client
->max_ratio
< nw
)
509 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
512 if (*dw
!= trydw
) { /* got resisted */
513 /* resize the height based on the width */
514 if (moveresize_client
->min_ratio
) {
515 if (nh
* moveresize_client
->min_ratio
> nw
)
516 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
518 if (moveresize_client
->max_ratio
) {
519 if (nh
* moveresize_client
->max_ratio
< nw
)
520 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
525 /* make sure it's all valid */
526 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
532 static gboolean
edge_warp_delay_func(gpointer data
)
536 /* only fire every second time. so it's fast the first time, but slower
539 d
= screen_find_desktop(screen_desktop
, edge_warp_dir
, TRUE
, FALSE
);
540 if (d
!= screen_desktop
) screen_set_desktop(d
, TRUE
);
542 edge_warp_odd
= !edge_warp_odd
;
544 return TRUE
; /* do repeat ! */
547 static void do_edge_warp(gint x
, gint y
)
552 if (!config_mouse_screenedgetime
) return;
556 for (i
= 0; i
< screen_num_monitors
; ++i
) {
557 Rect
*a
= screen_physical_area_monitor(i
);
558 if (x
== RECT_LEFT(*a
)) dir
= OB_DIRECTION_WEST
;
559 if (x
== RECT_RIGHT(*a
)) dir
= OB_DIRECTION_EAST
;
560 if (y
== RECT_TOP(*a
)) dir
= OB_DIRECTION_NORTH
;
561 if (y
== RECT_BOTTOM(*a
)) dir
= OB_DIRECTION_SOUTH
;
563 /* try check for xinerama boundaries */
564 if ((x
+ 1 == RECT_LEFT(*a
) || x
- 1 == RECT_RIGHT(*a
)) &&
565 (dir
== OB_DIRECTION_WEST
|| dir
== OB_DIRECTION_EAST
))
569 if ((y
+ 1 == RECT_TOP(*a
) || y
- 1 == RECT_BOTTOM(*a
)) &&
570 (dir
== OB_DIRECTION_NORTH
|| dir
== OB_DIRECTION_SOUTH
))
577 if (dir
!= edge_warp_dir
) {
579 if (dir
!= (ObDirection
)-1) {
580 edge_warp_odd
= TRUE
; /* switch on the first timeout */
581 ob_main_loop_timeout_add(ob_main_loop
,
582 config_mouse_screenedgetime
* 1000,
583 edge_warp_delay_func
,
590 static void cancel_edge_warp(void)
592 ob_main_loop_timeout_remove(ob_main_loop
, edge_warp_delay_func
);
595 static void move_with_keys(gint keycode
, gint state
)
597 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
598 gint opx
, px
, opy
, py
;
601 /* shift means jump to edge */
602 if (state
& modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT
)) {
606 if (keycode
== ob_keycode(OB_KEY_RIGHT
))
607 dir
= OB_DIRECTION_EAST
;
608 else if (keycode
== ob_keycode(OB_KEY_LEFT
))
609 dir
= OB_DIRECTION_WEST
;
610 else if (keycode
== ob_keycode(OB_KEY_DOWN
))
611 dir
= OB_DIRECTION_SOUTH
;
612 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
613 dir
= OB_DIRECTION_NORTH
;
615 client_find_move_directional(moveresize_client
, dir
, &x
, &y
);
616 dx
= x
- moveresize_client
->area
.x
;
617 dy
= y
- moveresize_client
->area
.y
;
619 /* control means fine grained */
620 if (state
& modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL
))
625 if (keycode
== ob_keycode(OB_KEY_RIGHT
))
627 else if (keycode
== ob_keycode(OB_KEY_LEFT
))
629 else if (keycode
== ob_keycode(OB_KEY_DOWN
))
631 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
635 screen_pointer_pos(&opx
, &opy
);
636 XWarpPointer(ob_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
637 /* steal the motion events this causes */
638 XSync(ob_display
, FALSE
);
641 while (XCheckTypedEvent(ob_display
, MotionNotify
, &ce
));
643 screen_pointer_pos(&px
, &py
);
649 /* because the cursor moves even though the window does
650 not nessesarily (resistance), this adjusts where the curor
651 thinks it started so that it keeps up with where the window
653 start_x
+= (px
- opx
) - (cur_x
- ox
);
654 start_y
+= (py
- opy
) - (cur_y
- oy
);
657 static void resize_with_keys(gint keycode
, gint state
)
659 gint dw
= 0, dh
= 0, pdx
= 0, pdy
= 0, opx
, opy
, px
, py
;
660 gint dist
= 0, resist
= 0;
663 /* pick the edge if it needs to move */
664 if (keycode
== ob_keycode(OB_KEY_RIGHT
)) {
665 dir
= OB_DIRECTION_EAST
;
666 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
667 key_resize_edge
!= OB_DIRECTION_EAST
)
669 key_resize_edge
= OB_DIRECTION_EAST
;
673 if (keycode
== ob_keycode(OB_KEY_LEFT
)) {
674 dir
= OB_DIRECTION_WEST
;
675 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
676 key_resize_edge
!= OB_DIRECTION_EAST
)
678 key_resize_edge
= OB_DIRECTION_WEST
;
682 if (keycode
== ob_keycode(OB_KEY_UP
)) {
683 dir
= OB_DIRECTION_NORTH
;
684 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
685 key_resize_edge
!= OB_DIRECTION_SOUTH
)
687 key_resize_edge
= OB_DIRECTION_NORTH
;
691 if (keycode
== ob_keycode(OB_KEY_DOWN
)) {
692 dir
= OB_DIRECTION_SOUTH
;
693 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
694 key_resize_edge
!= OB_DIRECTION_SOUTH
)
696 key_resize_edge
= OB_DIRECTION_SOUTH
;
701 /* shift means jump to edge */
702 if (state
& modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT
)) {
705 if (keycode
== ob_keycode(OB_KEY_RIGHT
))
706 dir
= OB_DIRECTION_EAST
;
707 else if (keycode
== ob_keycode(OB_KEY_LEFT
))
708 dir
= OB_DIRECTION_WEST
;
709 else if (keycode
== ob_keycode(OB_KEY_DOWN
))
710 dir
= OB_DIRECTION_SOUTH
;
711 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
712 dir
= OB_DIRECTION_NORTH
;
714 client_find_resize_directional(moveresize_client
, key_resize_edge
,
715 key_resize_edge
== dir
,
717 dw
= w
- moveresize_client
->area
.width
;
718 dh
= h
- moveresize_client
->area
.height
;
722 /* control means fine grained */
723 if (moveresize_client
->size_inc
.width
> 1) {
724 distw
= moveresize_client
->size_inc
.width
;
727 else if (state
& modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL
)) {
735 if (moveresize_client
->size_inc
.height
> 1) {
736 disth
= moveresize_client
->size_inc
.height
;
739 else if (state
& modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL
)) {
748 if (key_resize_edge
== OB_DIRECTION_WEST
) {
749 if (dir
== OB_DIRECTION_WEST
)
752 dw
= -(dist
= distw
);
754 else if (key_resize_edge
== OB_DIRECTION_EAST
) {
755 if (dir
== OB_DIRECTION_EAST
)
758 dw
= -(dist
= distw
);
760 else if (key_resize_edge
== OB_DIRECTION_NORTH
) {
761 if (dir
== OB_DIRECTION_NORTH
)
764 dh
= -(dist
= disth
);
766 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
767 if (dir
== OB_DIRECTION_SOUTH
)
770 dh
= -(dist
= disth
);
774 calc_resize(TRUE
, resist
, &dw
, &dh
, dir
);
775 if (key_resize_edge
== OB_DIRECTION_WEST
)
777 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
782 /* how to move the pointer to keep up with the change */
783 if (key_resize_edge
== OB_DIRECTION_WEST
)
785 else if (key_resize_edge
== OB_DIRECTION_EAST
)
787 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
789 else if (key_resize_edge
== OB_DIRECTION_SOUTH
)
792 screen_pointer_pos(&opx
, &opy
);
793 XWarpPointer(ob_display
, None
, None
, 0, 0, 0, 0, pdx
, pdy
);
794 /* steal the motion events this causes */
795 XSync(ob_display
, FALSE
);
798 while (XCheckTypedEvent(ob_display
, MotionNotify
, &ce
));
800 screen_pointer_pos(&px
, &py
);
804 /* because the cursor moves even though the window does
805 not nessesarily (resistance), this adjusts where the cursor
806 thinks it started so that it keeps up with where the window
808 start_x
+= (px
- opx
) - dw
;
809 start_y
+= (py
- opy
) - dh
;
813 gboolean
moveresize_event(XEvent
*e
)
815 gboolean used
= FALSE
;
817 if (!moveresize_in_progress
) return FALSE
;
819 if (e
->type
== ButtonPress
) {
821 start_x
= e
->xbutton
.x_root
;
822 start_y
= e
->xbutton
.y_root
;
823 button
= e
->xbutton
.button
; /* this will end it now */
825 used
= e
->xbutton
.button
== button
;
826 } else if (e
->type
== ButtonRelease
) {
827 if (!button
|| e
->xbutton
.button
== button
) {
828 moveresize_end(FALSE
);
831 } else if (e
->type
== MotionNotify
) {
833 cur_x
= start_cx
+ e
->xmotion
.x_root
- start_x
;
834 cur_y
= start_cy
+ e
->xmotion
.y_root
- start_y
;
836 do_edge_warp(e
->xmotion
.x_root
, e
->xmotion
.y_root
);
841 if (corner
== prop_atoms
.net_wm_moveresize_size_topleft
) {
842 dw
= -(e
->xmotion
.x_root
- start_x
);
843 dh
= -(e
->xmotion
.y_root
- start_y
);
844 dir
= OB_DIRECTION_NORTHWEST
;
845 } else if (corner
== prop_atoms
.net_wm_moveresize_size_top
) {
847 dh
= -(e
->xmotion
.y_root
- start_y
);
848 dir
= OB_DIRECTION_NORTH
;
849 } else if (corner
== prop_atoms
.net_wm_moveresize_size_topright
) {
850 dw
= (e
->xmotion
.x_root
- start_x
);
851 dh
= -(e
->xmotion
.y_root
- start_y
);
852 dir
= OB_DIRECTION_NORTHEAST
;
853 } else if (corner
== prop_atoms
.net_wm_moveresize_size_right
) {
854 dw
= (e
->xmotion
.x_root
- start_x
);
856 dir
= OB_DIRECTION_EAST
;
858 prop_atoms
.net_wm_moveresize_size_bottomright
) {
859 dw
= (e
->xmotion
.x_root
- start_x
);
860 dh
= (e
->xmotion
.y_root
- start_y
);
861 dir
= OB_DIRECTION_SOUTHEAST
;
862 } else if (corner
== prop_atoms
.net_wm_moveresize_size_bottom
) {
864 dh
= (e
->xmotion
.y_root
- start_y
);
865 dir
= OB_DIRECTION_SOUTH
;
867 prop_atoms
.net_wm_moveresize_size_bottomleft
) {
868 dw
= -(e
->xmotion
.x_root
- start_x
);
869 dh
= (e
->xmotion
.y_root
- start_y
);
870 dir
= OB_DIRECTION_SOUTHWEST
;
871 } else if (corner
== prop_atoms
.net_wm_moveresize_size_left
) {
872 dw
= -(e
->xmotion
.x_root
- start_x
);
874 dir
= OB_DIRECTION_WEST
;
875 } else if (corner
== prop_atoms
.net_wm_moveresize_size_keyboard
) {
876 dw
= (e
->xmotion
.x_root
- start_x
);
877 dh
= (e
->xmotion
.y_root
- start_y
);
878 dir
= OB_DIRECTION_SOUTHEAST
;
880 g_assert_not_reached();
882 dw
-= cur_w
- start_cw
;
883 dh
-= cur_h
- start_ch
;
885 calc_resize(FALSE
, 0, &dw
, &dh
, dir
);
889 if (corner
== prop_atoms
.net_wm_moveresize_size_topleft
||
890 corner
== prop_atoms
.net_wm_moveresize_size_left
||
891 corner
== prop_atoms
.net_wm_moveresize_size_bottomleft
)
895 if (corner
== prop_atoms
.net_wm_moveresize_size_topleft
||
896 corner
== prop_atoms
.net_wm_moveresize_size_top
||
897 corner
== prop_atoms
.net_wm_moveresize_size_topright
)
905 } else if (e
->type
== KeyPress
) {
906 if (e
->xkey
.keycode
== ob_keycode(OB_KEY_ESCAPE
)) {
907 moveresize_end(TRUE
);
909 } else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RETURN
)) {
910 moveresize_end(FALSE
);
912 } else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RIGHT
) ||
913 e
->xkey
.keycode
== ob_keycode(OB_KEY_LEFT
) ||
914 e
->xkey
.keycode
== ob_keycode(OB_KEY_DOWN
) ||
915 e
->xkey
.keycode
== ob_keycode(OB_KEY_UP
))
917 if (corner
== prop_atoms
.net_wm_moveresize_size_keyboard
) {
918 resize_with_keys(e
->xkey
.keycode
, e
->xkey
.state
);
920 } else if (corner
== prop_atoms
.net_wm_moveresize_move_keyboard
) {
921 move_with_keys(e
->xkey
.keycode
, e
->xkey
.state
);
927 else if (e
->type
== extensions_sync_event_basep
+ XSyncAlarmNotify
)
929 waiting_for_sync
= FALSE
; /* we got our sync... */
930 do_resize(); /* ...so try resize if there is more change pending */