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"
28 #include "moveresize.h"
32 #include "obrender/render.h"
33 #include "obrender/theme.h"
34 #include "obt/display.h"
36 #include "obt/keyboard.h"
41 /* how far windows move and resize with the keyboard arrows */
44 gboolean moveresize_in_progress
= FALSE
;
45 ObClient
*moveresize_client
= NULL
;
47 XSyncAlarm moveresize_alarm
= None
;
50 static gboolean moving
= FALSE
; /* TRUE - moving, FALSE - resizing */
52 static gint start_x
, start_y
, start_cx
, start_cy
, start_cw
, start_ch
;
53 static gint cur_x
, cur_y
, cur_w
, cur_h
;
55 static guint32 corner
;
56 static ObDirection edge_warp_dir
= -1;
57 static gboolean edge_warp_odd
= FALSE
;
58 static ObDirection key_resize_edge
= -1;
60 static gboolean waiting_for_sync
;
63 static ObPopup
*popup
= NULL
;
65 static void do_move(gboolean keyboard
, gint keydist
);
66 static void do_resize(void);
67 static void do_edge_warp(gint x
, gint y
);
68 static void cancel_edge_warp();
70 static gboolean
sync_timeout_func(gpointer data
);
73 static void client_dest(ObClient
*client
, gpointer data
)
75 if (moveresize_client
== client
)
79 void moveresize_startup(gboolean reconfig
)
82 popup_set_text_align(popup
, RR_JUSTIFY_CENTER
);
85 client_add_destroy_notify(client_dest
, NULL
);
88 void moveresize_shutdown(gboolean reconfig
)
91 if (moveresize_in_progress
)
92 moveresize_end(FALSE
);
93 client_remove_destroy_notify(client_dest
);
100 static void popup_coords(ObClient
*c
, const gchar
*format
, gint a
, gint b
)
104 text
= g_strdup_printf(format
, a
, b
);
105 if (config_resize_popup_pos
== OB_RESIZE_POS_TOP
)
106 popup_position(popup
, SouthGravity
,
108 + c
->frame
->area
.width
/2,
109 c
->frame
->area
.y
- ob_rr_theme
->fbwidth
);
110 else if (config_resize_popup_pos
== OB_RESIZE_POS_CENTER
)
111 popup_position(popup
, CenterGravity
,
112 c
->frame
->area
.x
+ c
->frame
->area
.width
/ 2,
113 c
->frame
->area
.y
+ c
->frame
->area
.height
/ 2);
115 Rect
*area
= screen_physical_area_active();
118 x
= config_resize_popup_fixed
.x
.pos
;
119 if (config_resize_popup_fixed
.x
.center
)
120 x
= area
->x
+ area
->width
/2;
121 else if (config_resize_popup_fixed
.x
.opposite
)
122 x
= RECT_RIGHT(*area
) - x
;
126 y
= config_resize_popup_fixed
.y
.pos
;
127 if (config_resize_popup_fixed
.y
.center
)
128 y
= area
->y
+ area
->height
/2;
129 else if (config_resize_popup_fixed
.y
.opposite
)
130 y
= RECT_RIGHT(*area
) - y
;
134 if (config_resize_popup_fixed
.x
.center
) {
135 if (config_resize_popup_fixed
.y
.center
)
136 gravity
= CenterGravity
;
137 else if (config_resize_popup_fixed
.y
.opposite
)
138 gravity
= SouthGravity
;
140 gravity
= NorthGravity
;
142 else if (config_resize_popup_fixed
.x
.opposite
) {
143 if (config_resize_popup_fixed
.y
.center
)
144 gravity
= EastGravity
;
145 else if (config_resize_popup_fixed
.y
.opposite
)
146 gravity
= SouthEastGravity
;
148 gravity
= NorthEastGravity
;
151 if (config_resize_popup_fixed
.y
.center
)
152 gravity
= WestGravity
;
153 else if (config_resize_popup_fixed
.y
.opposite
)
154 gravity
= SouthWestGravity
;
156 gravity
= NorthWestGravity
;
159 popup_position(popup
, gravity
, x
, y
);
163 popup_show(popup
, text
);
167 void moveresize_start(ObClient
*c
, gint x
, gint y
, guint b
, guint32 cnr
)
170 gboolean mv
= (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE
) ||
171 cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
));
175 if (moveresize_in_progress
|| !c
->frame
->visible
||
177 (c
->functions
& OB_CLIENT_FUNC_MOVE
) :
178 (c
->functions
& OB_CLIENT_FUNC_RESIZE
)))
181 if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
)) {
182 cur
= OB_CURSOR_NORTHWEST
;
185 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
)) {
186 cur
= OB_CURSOR_NORTH
;
189 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
)) {
190 cur
= OB_CURSOR_NORTHEAST
;
193 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT
))
194 cur
= OB_CURSOR_EAST
;
195 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
))
196 cur
= OB_CURSOR_SOUTHEAST
;
197 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM
))
198 cur
= OB_CURSOR_SOUTH
;
199 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
)) {
200 cur
= OB_CURSOR_SOUTHWEST
;
203 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
)) {
204 cur
= OB_CURSOR_WEST
;
207 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
))
208 cur
= OB_CURSOR_SOUTHEAST
;
209 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE
))
210 cur
= OB_CURSOR_MOVE
;
211 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
))
212 cur
= OB_CURSOR_MOVE
;
214 g_assert_not_reached();
216 /* keep the pointer bounded to the screen for move/resize */
217 if (!grab_pointer(FALSE
, TRUE
, cur
))
219 if (!grab_keyboard()) {
224 frame_end_iconify_animation(c
->frame
);
227 moveresize_client
= c
;
228 start_cx
= c
->area
.x
;
229 start_cy
= c
->area
.y
;
230 start_cw
= c
->area
.width
;
231 start_ch
= c
->area
.height
;
232 /* these adjustments for the size_inc make resizing a terminal more
233 friendly. you essentially start the resize in the middle of the
234 increment instead of at 0, so you have to move half an increment
235 either way instead of a full increment one and 1 px the other. */
236 start_x
= x
- (mv
? 0 : left
* c
->size_inc
.width
/ 2);
237 start_y
= y
- (mv
? 0 : up
* c
->size_inc
.height
/ 2);
240 key_resize_edge
= -1;
243 have to change start_cx and start_cy if going to do this..
244 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
245 corner == prop_atoms.net_wm_moveresize_size_keyboard)
246 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
247 c->area.width / 2, c->area.height / 2);
255 moveresize_in_progress
= TRUE
;
258 if (config_resize_redraw
&& !moving
&& obt_display_extension_sync
&&
259 moveresize_client
->sync_request
&& moveresize_client
->sync_counter
&&
260 !moveresize_client
->not_responding
)
262 /* Initialize values for the resize syncing, and create an alarm for
263 the client's xsync counter */
266 XSyncAlarmAttributes aa
;
268 /* set the counter to an initial value */
269 XSyncIntToValue(&val
, 0);
270 XSyncSetCounter(obt_display
, moveresize_client
->sync_counter
, val
);
272 /* this will be incremented when we tell the client what we're
274 moveresize_client
->sync_counter_value
= 0;
276 /* the next sequence we're waiting for with the alarm */
277 XSyncIntToValue(&val
, 1);
279 /* set an alarm on the counter */
280 aa
.trigger
.counter
= moveresize_client
->sync_counter
;
281 aa
.trigger
.wait_value
= val
;
282 aa
.trigger
.value_type
= XSyncAbsolute
;
283 aa
.trigger
.test_type
= XSyncPositiveTransition
;
285 XSyncIntToValue(&aa
.delta
, 1);
286 moveresize_alarm
= XSyncCreateAlarm(obt_display
,
295 waiting_for_sync
= FALSE
;
300 void moveresize_end(gboolean cancel
)
309 /* turn off the alarm */
310 if (moveresize_alarm
!= None
) {
311 XSyncDestroyAlarm(obt_display
, moveresize_alarm
);
312 moveresize_alarm
= None
;
315 obt_main_loop_timeout_remove(ob_main_loop
, sync_timeout_func
);
319 /* don't use client_move() here, use the same width/height as
320 we've been using during the move, otherwise we get different results
321 when moving maximized windows between monitors of different sizes !
323 client_configure(moveresize_client
,
324 (cancel
? start_cx
: cur_x
),
325 (cancel
? start_cy
: cur_y
),
326 (cancel
? start_cw
: cur_w
),
327 (cancel
? start_ch
: cur_h
),
330 /* dont edge warp after its ended */
333 moveresize_in_progress
= FALSE
;
334 moveresize_client
= NULL
;
337 static void do_move(gboolean keyboard
, gint keydist
)
341 if (keyboard
) resist
= keydist
- 1; /* resist for one key press */
342 else resist
= config_resist_win
;
343 resist_move_windows(moveresize_client
, resist
, &cur_x
, &cur_y
);
344 if (!keyboard
) resist
= config_resist_edge
;
345 resist_move_monitors(moveresize_client
, resist
, &cur_x
, &cur_y
);
347 client_configure(moveresize_client
, cur_x
, cur_y
, cur_w
, cur_h
,
349 if (config_resize_popup_show
== 2) /* == "Always" */
350 popup_coords(moveresize_client
, "%d x %d",
351 moveresize_client
->frame
->area
.x
,
352 moveresize_client
->frame
->area
.y
);
355 static void do_resize(void)
357 gint x
, y
, w
, h
, lw
, lh
;
359 /* see if it is actually going to resize */
364 client_try_configure(moveresize_client
, &x
, &y
, &w
, &h
,
366 if (!(w
== moveresize_client
->area
.width
&&
367 h
== moveresize_client
->area
.height
))
371 if (config_resize_redraw
&& obt_display_extension_sync
&&
372 moveresize_client
->sync_request
&& moveresize_client
->sync_counter
&&
373 !moveresize_client
->not_responding
)
378 /* are we already waiting for the sync counter to catch up? */
379 if (waiting_for_sync
)
382 /* increment the value we're waiting for */
383 ++moveresize_client
->sync_counter_value
;
384 XSyncIntToValue(&val
, moveresize_client
->sync_counter_value
);
386 /* tell the client what we're waiting for */
387 ce
.xclient
.type
= ClientMessage
;
388 ce
.xclient
.message_type
= OBT_PROP_ATOM(WM_PROTOCOLS
);
389 ce
.xclient
.display
= obt_display
;
390 ce
.xclient
.window
= moveresize_client
->window
;
391 ce
.xclient
.format
= 32;
392 ce
.xclient
.data
.l
[0] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST
);
393 ce
.xclient
.data
.l
[1] = event_curtime
;
394 ce
.xclient
.data
.l
[2] = XSyncValueLow32(val
);
395 ce
.xclient
.data
.l
[3] = XSyncValueHigh32(val
);
396 ce
.xclient
.data
.l
[4] = 0l;
397 XSendEvent(obt_display
, moveresize_client
->window
, FALSE
,
400 waiting_for_sync
= TRUE
;
402 obt_main_loop_timeout_remove(ob_main_loop
, sync_timeout_func
);
403 obt_main_loop_timeout_add(ob_main_loop
, G_USEC_PER_SEC
* 2,
409 client_configure(moveresize_client
, cur_x
, cur_y
, cur_w
, cur_h
,
413 /* this would be better with a fixed width font ... XXX can do it better
414 if there are 2 text boxes */
415 if (config_resize_popup_show
== 2 || /* == "Always" */
416 (config_resize_popup_show
== 1 && /* == "Nonpixel" */
417 moveresize_client
->size_inc
.width
> 1 &&
418 moveresize_client
->size_inc
.height
> 1))
419 popup_coords(moveresize_client
, "%d x %d", lw
, lh
);
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 */
432 static void calc_resize(gboolean keyboard
, gint keydist
, gint
*dw
, gint
*dh
,
435 gint resist
, x
= 0, y
= 0, lw
, lh
, ow
, oh
, nw
, nh
;
444 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
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
);
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
);
472 /* see its actual size (apply aspect ratios) */
473 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
,
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
;
499 /* take aspect ratios into account for resistance */
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
);
534 static gboolean
edge_warp_delay_func(gpointer data
)
538 /* only fire every second time. so it's fast the first time, but slower
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
)
554 if (!config_mouse_screenedgetime
) return;
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
))
571 if ((y
+ 1 == RECT_TOP(*a
) || y
- 1 == RECT_BOTTOM(*a
)) &&
572 (dir
== OB_DIRECTION_NORTH
|| dir
== OB_DIRECTION_SOUTH
))
579 if (dir
!= edge_warp_dir
) {
581 if (dir
!= (ObDirection
)-1) {
582 edge_warp_odd
= TRUE
; /* switch on the first timeout */
583 obt_main_loop_timeout_add(ob_main_loop
,
584 config_mouse_screenedgetime
* 1000,
585 edge_warp_delay_func
,
592 static void cancel_edge_warp(void)
594 obt_main_loop_timeout_remove(ob_main_loop
, edge_warp_delay_func
);
597 static void move_with_keys(KeySym sym
, guint state
)
599 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
600 gint opx
, px
, opy
, py
;
603 /* shift means jump to edge */
604 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
))
610 dir
= OB_DIRECTION_EAST
;
611 else if (sym
== XK_Left
)
612 dir
= OB_DIRECTION_WEST
;
613 else if (sym
== XK_Down
)
614 dir
= OB_DIRECTION_SOUTH
;
615 else /* sym == XK_Up */
616 dir
= OB_DIRECTION_NORTH
;
618 client_find_move_directional(moveresize_client
, dir
, &x
, &y
);
619 dx
= x
- moveresize_client
->area
.x
;
620 dy
= y
- moveresize_client
->area
.y
;
622 /* control means fine grained */
624 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
633 else if (sym
== XK_Left
)
635 else if (sym
== XK_Down
)
637 else /* if (sym == XK_Up) */
641 screen_pointer_pos(&opx
, &opy
);
642 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
643 /* steal the motion events this causes */
644 XSync(obt_display
, FALSE
);
647 while (XCheckTypedEvent(obt_display
, MotionNotify
, &ce
));
649 screen_pointer_pos(&px
, &py
);
655 /* because the cursor moves even though the window does
656 not nessesarily (resistance), this adjusts where the curor
657 thinks it started so that it keeps up with where the window
659 start_x
+= (px
- opx
) - (cur_x
- ox
);
660 start_y
+= (py
- opy
) - (cur_y
- oy
);
663 static void resize_with_keys(KeySym sym
, guint state
)
665 gint dw
= 0, dh
= 0, pdx
= 0, pdy
= 0, opx
, opy
, px
, py
;
669 /* pick the edge if it needs to move */
670 if (sym
== XK_Right
) {
671 dir
= OB_DIRECTION_EAST
;
672 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
673 key_resize_edge
!= OB_DIRECTION_EAST
)
675 key_resize_edge
= OB_DIRECTION_EAST
;
678 } else if (sym
== XK_Left
) {
679 dir
= OB_DIRECTION_WEST
;
680 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
681 key_resize_edge
!= OB_DIRECTION_EAST
)
683 key_resize_edge
= OB_DIRECTION_WEST
;
686 } else if (sym
== XK_Up
) {
687 dir
= OB_DIRECTION_NORTH
;
688 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
689 key_resize_edge
!= OB_DIRECTION_SOUTH
)
691 key_resize_edge
= OB_DIRECTION_NORTH
;
694 } else /* if (sym == XK_Down) */ {
695 dir
= OB_DIRECTION_SOUTH
;
696 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
697 key_resize_edge
!= OB_DIRECTION_SOUTH
)
699 key_resize_edge
= OB_DIRECTION_SOUTH
;
704 /* shift means jump to edge */
705 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
))
710 dir
= OB_DIRECTION_EAST
;
711 else if (sym
== XK_Left
)
712 dir
= OB_DIRECTION_WEST
;
713 else if (sym
== XK_Down
)
714 dir
= OB_DIRECTION_SOUTH
;
715 else /* if (sym == XK_Up)) */
716 dir
= OB_DIRECTION_NORTH
;
718 client_find_resize_directional(moveresize_client
, key_resize_edge
,
719 key_resize_edge
== dir
,
721 dw
= w
- moveresize_client
->area
.width
;
722 dh
= h
- moveresize_client
->area
.height
;
726 /* control means fine grained */
727 if (moveresize_client
->size_inc
.width
> 1) {
728 distw
= moveresize_client
->size_inc
.width
;
732 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
741 if (moveresize_client
->size_inc
.height
> 1) {
742 disth
= moveresize_client
->size_inc
.height
;
746 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
756 if (key_resize_edge
== OB_DIRECTION_WEST
) {
757 if (dir
== OB_DIRECTION_WEST
)
762 else if (key_resize_edge
== OB_DIRECTION_EAST
) {
763 if (dir
== OB_DIRECTION_EAST
)
768 else if (key_resize_edge
== OB_DIRECTION_NORTH
) {
769 if (dir
== OB_DIRECTION_NORTH
)
774 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
775 if (dir
== OB_DIRECTION_SOUTH
)
782 calc_resize(TRUE
, resist
, &dw
, &dh
, dir
);
783 if (key_resize_edge
== OB_DIRECTION_WEST
)
785 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
790 /* how to move the pointer to keep up with the change */
791 if (key_resize_edge
== OB_DIRECTION_WEST
)
793 else if (key_resize_edge
== OB_DIRECTION_EAST
)
795 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
797 else if (key_resize_edge
== OB_DIRECTION_SOUTH
)
800 screen_pointer_pos(&opx
, &opy
);
801 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, pdx
, pdy
);
802 /* steal the motion events this causes */
803 XSync(obt_display
, FALSE
);
806 while (XCheckTypedEvent(obt_display
, MotionNotify
, &ce
));
808 screen_pointer_pos(&px
, &py
);
812 /* because the cursor moves even though the window does
813 not nessesarily (resistance), this adjusts where the cursor
814 thinks it started so that it keeps up with where the window
816 start_x
+= (px
- opx
) - dw
;
817 start_y
+= (py
- opy
) - dh
;
821 gboolean
moveresize_event(XEvent
*e
)
823 gboolean used
= FALSE
;
825 if (!moveresize_in_progress
) return FALSE
;
827 if (e
->type
== ButtonPress
) {
829 start_x
= e
->xbutton
.x_root
;
830 start_y
= e
->xbutton
.y_root
;
831 button
= e
->xbutton
.button
; /* this will end it now */
833 used
= e
->xbutton
.button
== button
;
834 } else if (e
->type
== ButtonRelease
) {
835 if (!button
|| e
->xbutton
.button
== button
) {
836 moveresize_end(FALSE
);
839 } else if (e
->type
== MotionNotify
) {
841 cur_x
= start_cx
+ e
->xmotion
.x_root
- start_x
;
842 cur_y
= start_cy
+ e
->xmotion
.y_root
- start_y
;
844 do_edge_warp(e
->xmotion
.x_root
, e
->xmotion
.y_root
);
849 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
)) {
850 dw
= -(e
->xmotion
.x_root
- start_x
);
851 dh
= -(e
->xmotion
.y_root
- start_y
);
852 dir
= OB_DIRECTION_NORTHWEST
;
853 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
)) {
855 dh
= -(e
->xmotion
.y_root
- start_y
);
856 dir
= OB_DIRECTION_NORTH
;
858 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
)) {
859 dw
= (e
->xmotion
.x_root
- start_x
);
860 dh
= -(e
->xmotion
.y_root
- start_y
);
861 dir
= OB_DIRECTION_NORTHEAST
;
862 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT
)) {
863 dw
= (e
->xmotion
.x_root
- start_x
);
865 dir
= OB_DIRECTION_EAST
;
867 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
)) {
868 dw
= (e
->xmotion
.x_root
- start_x
);
869 dh
= (e
->xmotion
.y_root
- start_y
);
870 dir
= OB_DIRECTION_SOUTHEAST
;
871 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM
))
874 dh
= (e
->xmotion
.y_root
- start_y
);
875 dir
= OB_DIRECTION_SOUTH
;
877 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
)) {
878 dw
= -(e
->xmotion
.x_root
- start_x
);
879 dh
= (e
->xmotion
.y_root
- start_y
);
880 dir
= OB_DIRECTION_SOUTHWEST
;
881 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
)) {
882 dw
= -(e
->xmotion
.x_root
- start_x
);
884 dir
= OB_DIRECTION_WEST
;
886 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
887 dw
= (e
->xmotion
.x_root
- start_x
);
888 dh
= (e
->xmotion
.y_root
- start_y
);
889 dir
= OB_DIRECTION_SOUTHEAST
;
891 g_assert_not_reached();
893 dw
-= cur_w
- start_cw
;
894 dh
-= cur_h
- start_ch
;
896 calc_resize(FALSE
, 0, &dw
, &dh
, dir
);
900 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
901 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
) ||
902 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
))
906 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
907 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
) ||
908 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
))
916 } else if (e
->type
== KeyPress
) {
917 KeySym sym
= obt_keyboard_keypress_to_keysym(e
);
919 if (sym
== XK_Escape
) {
920 moveresize_end(TRUE
);
922 } else if (sym
== XK_Return
) {
923 moveresize_end(FALSE
);
925 } else if (sym
== XK_Right
|| sym
== XK_Left
||
926 sym
== XK_Up
|| sym
== XK_Down
)
928 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
929 resize_with_keys(sym
, e
->xkey
.state
);
932 OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
))
934 move_with_keys(sym
, e
->xkey
.state
);
940 else if (e
->type
== obt_display_extension_sync_basep
+ XSyncAlarmNotify
)
942 waiting_for_sync
= FALSE
; /* we got our sync... */
943 do_resize(); /* ...so try resize if there is more change pending */