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 const 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
);
161 popup_show(popup
, text
);
165 void moveresize_start(ObClient
*c
, gint x
, gint y
, guint b
, guint32 cnr
)
168 gboolean mv
= (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE
) ||
169 cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
));
173 if (moveresize_in_progress
|| !c
->frame
->visible
||
175 (c
->functions
& OB_CLIENT_FUNC_MOVE
) :
176 (c
->functions
& OB_CLIENT_FUNC_RESIZE
)))
179 if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
)) {
180 cur
= OB_CURSOR_NORTHWEST
;
183 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
)) {
184 cur
= OB_CURSOR_NORTH
;
187 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
)) {
188 cur
= OB_CURSOR_NORTHEAST
;
191 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT
))
192 cur
= OB_CURSOR_EAST
;
193 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
))
194 cur
= OB_CURSOR_SOUTHEAST
;
195 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM
))
196 cur
= OB_CURSOR_SOUTH
;
197 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
)) {
198 cur
= OB_CURSOR_SOUTHWEST
;
201 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
)) {
202 cur
= OB_CURSOR_WEST
;
205 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
))
206 cur
= OB_CURSOR_SOUTHEAST
;
207 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE
))
208 cur
= OB_CURSOR_MOVE
;
209 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
))
210 cur
= OB_CURSOR_MOVE
;
212 g_assert_not_reached();
214 /* keep the pointer bounded to the screen for move/resize */
215 if (!grab_pointer(FALSE
, TRUE
, cur
))
217 if (!grab_keyboard()) {
222 frame_end_iconify_animation(c
->frame
);
225 moveresize_client
= c
;
226 start_cx
= c
->area
.x
;
227 start_cy
= c
->area
.y
;
228 start_cw
= c
->area
.width
;
229 start_ch
= c
->area
.height
;
230 /* these adjustments for the size_inc make resizing a terminal more
231 friendly. you essentially start the resize in the middle of the
232 increment instead of at 0, so you have to move half an increment
233 either way instead of a full increment one and 1 px the other. */
234 start_x
= x
- (mv
? 0 : left
* c
->size_inc
.width
/ 2);
235 start_y
= y
- (mv
? 0 : up
* c
->size_inc
.height
/ 2);
238 key_resize_edge
= -1;
241 have to change start_cx and start_cy if going to do this..
242 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
243 corner == prop_atoms.net_wm_moveresize_size_keyboard)
244 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
245 c->area.width / 2, c->area.height / 2);
253 moveresize_in_progress
= TRUE
;
256 if (config_resize_redraw
&& !moving
&& obt_display_extension_sync
&&
257 moveresize_client
->sync_request
&& moveresize_client
->sync_counter
&&
258 !moveresize_client
->not_responding
)
260 /* Initialize values for the resize syncing, and create an alarm for
261 the client's xsync counter */
264 XSyncAlarmAttributes aa
;
266 /* set the counter to an initial value */
267 XSyncIntToValue(&val
, 0);
268 XSyncSetCounter(obt_display
, moveresize_client
->sync_counter
, val
);
270 /* this will be incremented when we tell the client what we're
272 moveresize_client
->sync_counter_value
= 0;
274 /* the next sequence we're waiting for with the alarm */
275 XSyncIntToValue(&val
, 1);
277 /* set an alarm on the counter */
278 aa
.trigger
.counter
= moveresize_client
->sync_counter
;
279 aa
.trigger
.wait_value
= val
;
280 aa
.trigger
.value_type
= XSyncAbsolute
;
281 aa
.trigger
.test_type
= XSyncPositiveTransition
;
283 XSyncIntToValue(&aa
.delta
, 1);
284 moveresize_alarm
= XSyncCreateAlarm(obt_display
,
293 waiting_for_sync
= FALSE
;
298 void moveresize_end(gboolean cancel
)
307 /* turn off the alarm */
308 if (moveresize_alarm
!= None
) {
309 XSyncDestroyAlarm(obt_display
, moveresize_alarm
);
310 moveresize_alarm
= None
;
313 obt_main_loop_timeout_remove(ob_main_loop
, sync_timeout_func
);
317 /* don't use client_move() here, use the same width/height as
318 we've been using during the move, otherwise we get different results
319 when moving maximized windows between monitors of different sizes !
321 client_configure(moveresize_client
,
322 (cancel
? start_cx
: cur_x
),
323 (cancel
? start_cy
: cur_y
),
324 (cancel
? start_cw
: cur_w
),
325 (cancel
? start_ch
: cur_h
),
328 /* dont edge warp after its ended */
331 moveresize_in_progress
= FALSE
;
332 moveresize_client
= NULL
;
335 static void do_move(gboolean keyboard
, gint keydist
)
339 if (keyboard
) resist
= keydist
- 1; /* resist for one key press */
340 else resist
= config_resist_win
;
341 resist_move_windows(moveresize_client
, resist
, &cur_x
, &cur_y
);
342 if (!keyboard
) resist
= config_resist_edge
;
343 resist_move_monitors(moveresize_client
, resist
, &cur_x
, &cur_y
);
345 client_configure(moveresize_client
, cur_x
, cur_y
, cur_w
, cur_h
,
347 if (config_resize_popup_show
== 2) /* == "Always" */
348 popup_coords(moveresize_client
, "%d x %d",
349 moveresize_client
->frame
->area
.x
,
350 moveresize_client
->frame
->area
.y
);
353 static void do_resize(void)
355 gint x
, y
, w
, h
, lw
, lh
;
357 /* see if it is actually going to resize */
362 client_try_configure(moveresize_client
, &x
, &y
, &w
, &h
,
364 if (!(w
== moveresize_client
->area
.width
&&
365 h
== moveresize_client
->area
.height
))
369 if (config_resize_redraw
&& obt_display_extension_sync
&&
370 moveresize_client
->sync_request
&& moveresize_client
->sync_counter
&&
371 !moveresize_client
->not_responding
)
376 /* are we already waiting for the sync counter to catch up? */
377 if (waiting_for_sync
)
380 /* increment the value we're waiting for */
381 ++moveresize_client
->sync_counter_value
;
382 XSyncIntToValue(&val
, moveresize_client
->sync_counter_value
);
384 /* tell the client what we're waiting for */
385 ce
.xclient
.type
= ClientMessage
;
386 ce
.xclient
.message_type
= OBT_PROP_ATOM(WM_PROTOCOLS
);
387 ce
.xclient
.display
= obt_display
;
388 ce
.xclient
.window
= moveresize_client
->window
;
389 ce
.xclient
.format
= 32;
390 ce
.xclient
.data
.l
[0] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST
);
391 ce
.xclient
.data
.l
[1] = event_time();
392 ce
.xclient
.data
.l
[2] = XSyncValueLow32(val
);
393 ce
.xclient
.data
.l
[3] = XSyncValueHigh32(val
);
394 ce
.xclient
.data
.l
[4] = 0l;
395 XSendEvent(obt_display
, moveresize_client
->window
, FALSE
,
398 waiting_for_sync
= TRUE
;
400 obt_main_loop_timeout_remove(ob_main_loop
, sync_timeout_func
);
401 obt_main_loop_timeout_add(ob_main_loop
, G_USEC_PER_SEC
* 2,
407 client_configure(moveresize_client
, cur_x
, cur_y
, cur_w
, cur_h
,
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", lw
, lh
);
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 void edge_warp_move_ptr(void)
537 screen_pointer_pos(&x
, &y
);
538 a
= screen_physical_area_all_monitors();
540 switch (edge_warp_dir
) {
541 case OB_DIRECTION_NORTH
:
544 case OB_DIRECTION_EAST
:
547 case OB_DIRECTION_SOUTH
:
550 case OB_DIRECTION_WEST
:
554 g_assert_not_reached();
557 XWarpPointer(obt_display
, 0, obt_root(ob_screen
), 0, 0, 0, 0, x
, y
);
560 static gboolean
edge_warp_delay_func(gpointer data
)
564 /* only fire every second time. so it's fast the first time, but slower
567 d
= screen_find_desktop(screen_desktop
, edge_warp_dir
, TRUE
, FALSE
);
568 if (d
!= screen_desktop
) {
569 if (config_mouse_screenedgewarp
) edge_warp_move_ptr();
570 screen_set_desktop(d
, TRUE
);
573 edge_warp_odd
= !edge_warp_odd
;
575 return TRUE
; /* do repeat ! */
578 static void do_edge_warp(gint x
, gint y
)
583 if (!config_mouse_screenedgetime
) return;
587 for (i
= 0; i
< screen_num_monitors
; ++i
) {
588 const Rect
*a
= screen_physical_area_monitor(i
);
589 if (x
== RECT_LEFT(*a
)) dir
= OB_DIRECTION_WEST
;
590 if (x
== RECT_RIGHT(*a
)) dir
= OB_DIRECTION_EAST
;
591 if (y
== RECT_TOP(*a
)) dir
= OB_DIRECTION_NORTH
;
592 if (y
== RECT_BOTTOM(*a
)) dir
= OB_DIRECTION_SOUTH
;
594 /* try check for xinerama boundaries */
595 if ((x
+ 1 == RECT_LEFT(*a
) || x
- 1 == RECT_RIGHT(*a
)) &&
596 (dir
== OB_DIRECTION_WEST
|| dir
== OB_DIRECTION_EAST
))
600 if ((y
+ 1 == RECT_TOP(*a
) || y
- 1 == RECT_BOTTOM(*a
)) &&
601 (dir
== OB_DIRECTION_NORTH
|| dir
== OB_DIRECTION_SOUTH
))
607 if (dir
!= edge_warp_dir
) {
609 if (dir
!= (ObDirection
)-1) {
610 edge_warp_odd
= TRUE
; /* switch on the first timeout */
611 obt_main_loop_timeout_add(ob_main_loop
,
612 config_mouse_screenedgetime
* 1000,
613 edge_warp_delay_func
,
620 static void cancel_edge_warp(void)
622 obt_main_loop_timeout_remove(ob_main_loop
, edge_warp_delay_func
);
625 static void move_with_keys(KeySym sym
, guint state
)
627 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
628 gint opx
, px
, opy
, py
;
631 /* shift means jump to edge */
632 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
))
638 dir
= OB_DIRECTION_EAST
;
639 else if (sym
== XK_Left
)
640 dir
= OB_DIRECTION_WEST
;
641 else if (sym
== XK_Down
)
642 dir
= OB_DIRECTION_SOUTH
;
643 else /* sym == XK_Up */
644 dir
= OB_DIRECTION_NORTH
;
646 client_find_move_directional(moveresize_client
, dir
, &x
, &y
);
647 dx
= x
- moveresize_client
->area
.x
;
648 dy
= y
- moveresize_client
->area
.y
;
650 /* control means fine grained */
652 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
661 else if (sym
== XK_Left
)
663 else if (sym
== XK_Down
)
665 else /* if (sym == XK_Up) */
669 screen_pointer_pos(&opx
, &opy
);
670 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
671 /* steal the motion events this causes */
672 XSync(obt_display
, FALSE
);
675 while (XCheckTypedEvent(obt_display
, MotionNotify
, &ce
));
677 screen_pointer_pos(&px
, &py
);
683 /* because the cursor moves even though the window does
684 not nessesarily (resistance), this adjusts where the curor
685 thinks it started so that it keeps up with where the window
687 start_x
+= (px
- opx
) - (cur_x
- ox
);
688 start_y
+= (py
- opy
) - (cur_y
- oy
);
691 static void resize_with_keys(KeySym sym
, guint state
)
693 gint dw
= 0, dh
= 0, pdx
= 0, pdy
= 0, opx
, opy
, px
, py
;
697 /* pick the edge if it needs to move */
698 if (sym
== XK_Right
) {
699 dir
= OB_DIRECTION_EAST
;
700 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
701 key_resize_edge
!= OB_DIRECTION_EAST
)
703 key_resize_edge
= OB_DIRECTION_EAST
;
706 } else if (sym
== XK_Left
) {
707 dir
= OB_DIRECTION_WEST
;
708 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
709 key_resize_edge
!= OB_DIRECTION_EAST
)
711 key_resize_edge
= OB_DIRECTION_WEST
;
714 } else if (sym
== XK_Up
) {
715 dir
= OB_DIRECTION_NORTH
;
716 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
717 key_resize_edge
!= OB_DIRECTION_SOUTH
)
719 key_resize_edge
= OB_DIRECTION_NORTH
;
722 } else /* if (sym == XK_Down) */ {
723 dir
= OB_DIRECTION_SOUTH
;
724 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
725 key_resize_edge
!= OB_DIRECTION_SOUTH
)
727 key_resize_edge
= OB_DIRECTION_SOUTH
;
732 /* shift means jump to edge */
733 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
))
738 dir
= OB_DIRECTION_EAST
;
739 else if (sym
== XK_Left
)
740 dir
= OB_DIRECTION_WEST
;
741 else if (sym
== XK_Down
)
742 dir
= OB_DIRECTION_SOUTH
;
743 else /* if (sym == XK_Up)) */
744 dir
= OB_DIRECTION_NORTH
;
746 client_find_resize_directional(moveresize_client
, key_resize_edge
,
747 key_resize_edge
== dir
,
749 dw
= w
- moveresize_client
->area
.width
;
750 dh
= h
- moveresize_client
->area
.height
;
754 /* control means fine grained */
755 if (moveresize_client
->size_inc
.width
> 1) {
756 distw
= moveresize_client
->size_inc
.width
;
760 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
769 if (moveresize_client
->size_inc
.height
> 1) {
770 disth
= moveresize_client
->size_inc
.height
;
774 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
784 if (key_resize_edge
== OB_DIRECTION_WEST
) {
785 if (dir
== OB_DIRECTION_WEST
)
790 else if (key_resize_edge
== OB_DIRECTION_EAST
) {
791 if (dir
== OB_DIRECTION_EAST
)
796 else if (key_resize_edge
== OB_DIRECTION_NORTH
) {
797 if (dir
== OB_DIRECTION_NORTH
)
802 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
803 if (dir
== OB_DIRECTION_SOUTH
)
810 calc_resize(TRUE
, resist
, &dw
, &dh
, dir
);
811 if (key_resize_edge
== OB_DIRECTION_WEST
)
813 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
818 /* how to move the pointer to keep up with the change */
819 if (key_resize_edge
== OB_DIRECTION_WEST
)
821 else if (key_resize_edge
== OB_DIRECTION_EAST
)
823 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
825 else if (key_resize_edge
== OB_DIRECTION_SOUTH
)
828 screen_pointer_pos(&opx
, &opy
);
829 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, pdx
, pdy
);
830 /* steal the motion events this causes */
831 XSync(obt_display
, FALSE
);
834 while (XCheckTypedEvent(obt_display
, MotionNotify
, &ce
));
836 screen_pointer_pos(&px
, &py
);
840 /* because the cursor moves even though the window does
841 not nessesarily (resistance), this adjusts where the cursor
842 thinks it started so that it keeps up with where the window
844 start_x
+= (px
- opx
) - dw
;
845 start_y
+= (py
- opy
) - dh
;
849 gboolean
moveresize_event(XEvent
*e
)
851 gboolean used
= FALSE
;
853 if (!moveresize_in_progress
) return FALSE
;
855 if (e
->type
== ButtonPress
) {
857 start_x
= e
->xbutton
.x_root
;
858 start_y
= e
->xbutton
.y_root
;
859 button
= e
->xbutton
.button
; /* this will end it now */
861 used
= e
->xbutton
.button
== button
;
862 } else if (e
->type
== ButtonRelease
) {
863 if (!button
|| e
->xbutton
.button
== button
) {
864 moveresize_end(FALSE
);
867 } else if (e
->type
== MotionNotify
) {
869 cur_x
= start_cx
+ e
->xmotion
.x_root
- start_x
;
870 cur_y
= start_cy
+ e
->xmotion
.y_root
- start_y
;
872 do_edge_warp(e
->xmotion
.x_root
, e
->xmotion
.y_root
);
877 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
)) {
878 dw
= -(e
->xmotion
.x_root
- start_x
);
879 dh
= -(e
->xmotion
.y_root
- start_y
);
880 dir
= OB_DIRECTION_NORTHWEST
;
881 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
)) {
883 dh
= -(e
->xmotion
.y_root
- start_y
);
884 dir
= OB_DIRECTION_NORTH
;
886 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
)) {
887 dw
= (e
->xmotion
.x_root
- start_x
);
888 dh
= -(e
->xmotion
.y_root
- start_y
);
889 dir
= OB_DIRECTION_NORTHEAST
;
890 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT
)) {
891 dw
= (e
->xmotion
.x_root
- start_x
);
893 dir
= OB_DIRECTION_EAST
;
895 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
)) {
896 dw
= (e
->xmotion
.x_root
- start_x
);
897 dh
= (e
->xmotion
.y_root
- start_y
);
898 dir
= OB_DIRECTION_SOUTHEAST
;
899 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM
))
902 dh
= (e
->xmotion
.y_root
- start_y
);
903 dir
= OB_DIRECTION_SOUTH
;
905 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
)) {
906 dw
= -(e
->xmotion
.x_root
- start_x
);
907 dh
= (e
->xmotion
.y_root
- start_y
);
908 dir
= OB_DIRECTION_SOUTHWEST
;
909 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
)) {
910 dw
= -(e
->xmotion
.x_root
- start_x
);
912 dir
= OB_DIRECTION_WEST
;
914 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
915 dw
= (e
->xmotion
.x_root
- start_x
);
916 dh
= (e
->xmotion
.y_root
- start_y
);
917 dir
= OB_DIRECTION_SOUTHEAST
;
919 g_assert_not_reached();
921 dw
-= cur_w
- start_cw
;
922 dh
-= cur_h
- start_ch
;
924 calc_resize(FALSE
, 0, &dw
, &dh
, dir
);
928 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
929 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
) ||
930 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
))
934 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
935 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
) ||
936 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
))
944 } else if (e
->type
== KeyPress
) {
945 KeySym sym
= obt_keyboard_keypress_to_keysym(e
);
947 if (sym
== XK_Escape
) {
948 moveresize_end(TRUE
);
950 } else if (sym
== XK_Return
|| sym
== XK_KP_Enter
) {
951 moveresize_end(FALSE
);
953 } else if (sym
== XK_Right
|| sym
== XK_Left
||
954 sym
== XK_Up
|| sym
== XK_Down
)
956 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
957 resize_with_keys(sym
, e
->xkey
.state
);
960 OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
))
962 move_with_keys(sym
, e
->xkey
.state
);
968 else if (e
->type
== obt_display_extension_sync_basep
+ XSyncAlarmNotify
)
970 waiting_for_sync
= FALSE
; /* we got our sync... */
971 do_resize(); /* ...so try resize if there is more change pending */