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 "render/render.h"
33 #include "render/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_edge_warp(gint x
, gint y
);
66 static void cancel_edge_warp();
68 static gboolean
sync_timeout_func(gpointer data
);
71 static void client_dest(ObClient
*client
, gpointer data
)
73 if (moveresize_client
== client
)
77 void moveresize_startup(gboolean reconfig
)
80 popup_set_text_align(popup
, RR_JUSTIFY_CENTER
);
83 client_add_destroy_notify(client_dest
, NULL
);
86 void moveresize_shutdown(gboolean reconfig
)
89 if (moveresize_in_progress
)
90 moveresize_end(FALSE
);
91 client_remove_destroy_notify(client_dest
);
98 static void popup_coords(ObClient
*c
, const gchar
*format
, gint a
, gint b
)
102 text
= g_strdup_printf(format
, a
, b
);
103 if (config_resize_popup_pos
== OB_RESIZE_POS_TOP
)
104 popup_position(popup
, SouthGravity
,
106 + c
->frame
->area
.width
/2,
107 c
->frame
->area
.y
- ob_rr_theme
->fbwidth
);
108 else if (config_resize_popup_pos
== OB_RESIZE_POS_CENTER
)
109 popup_position(popup
, CenterGravity
,
110 c
->frame
->area
.x
+ c
->frame
->size
.left
+
112 c
->frame
->area
.y
+ c
->frame
->size
.top
+
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
)
308 client_move(moveresize_client
,
309 (cancel
? start_cx
: cur_x
),
310 (cancel
? start_cy
: cur_y
));
313 /* turn off the alarm */
314 if (moveresize_alarm
!= None
) {
315 XSyncDestroyAlarm(obt_display
, moveresize_alarm
);
316 moveresize_alarm
= None
;
319 obt_main_loop_timeout_remove(ob_main_loop
, sync_timeout_func
);
322 client_configure(moveresize_client
,
323 (cancel
? start_cx
: cur_x
),
324 (cancel
? start_cy
: cur_y
),
325 (cancel
? start_cw
: cur_w
),
326 (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
);
356 static void do_resize(void)
358 gint x
, y
, w
, h
, lw
, lh
;
360 /* see if it is actually going to resize */
365 client_try_configure(moveresize_client
, &x
, &y
, &w
, &h
,
367 if (w
== moveresize_client
->area
.width
&&
368 h
== moveresize_client
->area
.height
)
374 if (config_resize_redraw
&& obt_display_extension_sync
&&
375 moveresize_client
->sync_request
&& moveresize_client
->sync_counter
&&
376 !moveresize_client
->not_responding
)
381 /* are we already waiting for the sync counter to catch up? */
382 if (waiting_for_sync
)
385 /* increment the value we're waiting for */
386 ++moveresize_client
->sync_counter_value
;
387 XSyncIntToValue(&val
, moveresize_client
->sync_counter_value
);
389 /* tell the client what we're waiting for */
390 ce
.xclient
.type
= ClientMessage
;
391 ce
.xclient
.message_type
= OBT_PROP_ATOM(WM_PROTOCOLS
);
392 ce
.xclient
.display
= obt_display
;
393 ce
.xclient
.window
= moveresize_client
->window
;
394 ce
.xclient
.format
= 32;
395 ce
.xclient
.data
.l
[0] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST
);
396 ce
.xclient
.data
.l
[1] = event_curtime
;
397 ce
.xclient
.data
.l
[2] = XSyncValueLow32(val
);
398 ce
.xclient
.data
.l
[3] = XSyncValueHigh32(val
);
399 ce
.xclient
.data
.l
[4] = 0l;
400 XSendEvent(obt_display
, moveresize_client
->window
, FALSE
,
403 waiting_for_sync
= TRUE
;
405 obt_main_loop_timeout_remove(ob_main_loop
, sync_timeout_func
);
406 obt_main_loop_timeout_add(ob_main_loop
, G_USEC_PER_SEC
* 2,
412 client_configure(moveresize_client
, cur_x
, cur_y
, cur_w
, cur_h
,
415 /* this would be better with a fixed width font ... XXX can do it better
416 if there are 2 text boxes */
417 if (config_resize_popup_show
== 2 || /* == "Always" */
418 (config_resize_popup_show
== 1 && /* == "Nonpixel" */
419 moveresize_client
->size_inc
.width
> 1 &&
420 moveresize_client
->size_inc
.height
> 1))
421 popup_coords(moveresize_client
, "%d x %d",
422 moveresize_client
->logical_size
.width
,
423 moveresize_client
->logical_size
.height
);
427 static gboolean
sync_timeout_func(gpointer data
)
429 waiting_for_sync
= FALSE
; /* we timed out waiting for our sync... */
430 do_resize(); /* ...so let any pending resizes through */
432 return FALSE
; /* don't repeat */
436 static void calc_resize(gboolean keyboard
, gint keydist
, gint
*dw
, gint
*dh
,
439 gint resist
, x
= 0, y
= 0, lw
, lh
, ow
, oh
, nw
, nh
;
448 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
451 case OB_DIRECTION_NORTH
:
452 case OB_DIRECTION_SOUTH
:
453 /* resize the width based on the height */
454 if (moveresize_client
->min_ratio
) {
455 if (nh
* moveresize_client
->min_ratio
> nw
)
456 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
458 if (moveresize_client
->max_ratio
) {
459 if (nh
* moveresize_client
->max_ratio
< nw
)
460 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
464 /* resize the height based on the width */
465 if (moveresize_client
->min_ratio
) {
466 if (nh
* moveresize_client
->min_ratio
> nw
)
467 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
469 if (moveresize_client
->max_ratio
) {
470 if (nh
* moveresize_client
->max_ratio
< nw
)
471 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
476 /* see its actual size (apply aspect ratios) */
477 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
,
483 /* resist_size_* needs the frame size */
484 nw
+= moveresize_client
->frame
->size
.left
+
485 moveresize_client
->frame
->size
.right
;
486 nh
+= moveresize_client
->frame
->size
.top
+
487 moveresize_client
->frame
->size
.bottom
;
489 if (keyboard
) resist
= keydist
- 1; /* resist for one key press */
490 else resist
= config_resist_win
;
491 resist_size_windows(moveresize_client
, resist
, &nw
, &nh
, dir
);
492 if (!keyboard
) resist
= config_resist_edge
;
493 resist_size_monitors(moveresize_client
, resist
, &nw
, &nh
, dir
);
495 nw
-= moveresize_client
->frame
->size
.left
+
496 moveresize_client
->frame
->size
.right
;
497 nh
-= moveresize_client
->frame
->size
.top
+
498 moveresize_client
->frame
->size
.bottom
;
503 /* take aspect ratios into account for resistance */
505 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
507 if (*dh
!= trydh
) { /* got resisted */
508 /* resize the width based on the height */
509 if (moveresize_client
->min_ratio
) {
510 if (nh
* moveresize_client
->min_ratio
> nw
)
511 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
513 if (moveresize_client
->max_ratio
) {
514 if (nh
* moveresize_client
->max_ratio
< nw
)
515 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
518 if (*dw
!= trydw
) { /* got resisted */
519 /* resize the height based on the width */
520 if (moveresize_client
->min_ratio
) {
521 if (nh
* moveresize_client
->min_ratio
> nw
)
522 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
524 if (moveresize_client
->max_ratio
) {
525 if (nh
* moveresize_client
->max_ratio
< nw
)
526 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
531 /* make sure it's all valid */
532 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
538 static gboolean
edge_warp_delay_func(gpointer data
)
542 /* only fire every second time. so it's fast the first time, but slower
545 d
= screen_find_desktop(screen_desktop
, edge_warp_dir
, TRUE
, FALSE
);
546 if (d
!= screen_desktop
) screen_set_desktop(d
, TRUE
);
548 edge_warp_odd
= !edge_warp_odd
;
550 return TRUE
; /* do repeat ! */
553 static void do_edge_warp(gint x
, gint y
)
558 if (!config_mouse_screenedgetime
) return;
562 for (i
= 0; i
< screen_num_monitors
; ++i
) {
563 Rect
*a
= screen_physical_area_monitor(i
);
564 if (x
== RECT_LEFT(*a
)) dir
= OB_DIRECTION_WEST
;
565 if (x
== RECT_RIGHT(*a
)) dir
= OB_DIRECTION_EAST
;
566 if (y
== RECT_TOP(*a
)) dir
= OB_DIRECTION_NORTH
;
567 if (y
== RECT_BOTTOM(*a
)) dir
= OB_DIRECTION_SOUTH
;
569 /* try check for xinerama boundaries */
570 if ((x
+ 1 == RECT_LEFT(*a
) || x
- 1 == RECT_RIGHT(*a
)) &&
571 (dir
== OB_DIRECTION_WEST
|| dir
== OB_DIRECTION_EAST
))
575 if ((y
+ 1 == RECT_TOP(*a
) || y
- 1 == RECT_BOTTOM(*a
)) &&
576 (dir
== OB_DIRECTION_NORTH
|| dir
== OB_DIRECTION_SOUTH
))
583 if (dir
!= edge_warp_dir
) {
585 if (dir
!= (ObDirection
)-1) {
586 edge_warp_odd
= TRUE
; /* switch on the first timeout */
587 obt_main_loop_timeout_add(ob_main_loop
,
588 config_mouse_screenedgetime
* 1000,
589 edge_warp_delay_func
,
596 static void cancel_edge_warp(void)
598 obt_main_loop_timeout_remove(ob_main_loop
, edge_warp_delay_func
);
601 static void move_with_keys(gint keycode
, gint state
)
603 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
604 gint opx
, px
, opy
, py
;
607 /* shift means jump to edge */
608 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
)) {
612 if (keycode
== ob_keycode(OB_KEY_RIGHT
))
613 dir
= OB_DIRECTION_EAST
;
614 else if (keycode
== ob_keycode(OB_KEY_LEFT
))
615 dir
= OB_DIRECTION_WEST
;
616 else if (keycode
== ob_keycode(OB_KEY_DOWN
))
617 dir
= OB_DIRECTION_SOUTH
;
618 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
619 dir
= OB_DIRECTION_NORTH
;
621 client_find_move_directional(moveresize_client
, dir
, &x
, &y
);
622 dx
= x
- moveresize_client
->area
.x
;
623 dy
= y
- moveresize_client
->area
.y
;
625 /* control means fine grained */
627 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
634 if (keycode
== ob_keycode(OB_KEY_RIGHT
))
636 else if (keycode
== ob_keycode(OB_KEY_LEFT
))
638 else if (keycode
== ob_keycode(OB_KEY_DOWN
))
640 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
644 screen_pointer_pos(&opx
, &opy
);
645 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
646 /* steal the motion events this causes */
647 XSync(obt_display
, FALSE
);
650 while (XCheckTypedEvent(obt_display
, MotionNotify
, &ce
));
652 screen_pointer_pos(&px
, &py
);
658 /* because the cursor moves even though the window does
659 not nessesarily (resistance), this adjusts where the curor
660 thinks it started so that it keeps up with where the window
662 start_x
+= (px
- opx
) - (cur_x
- ox
);
663 start_y
+= (py
- opy
) - (cur_y
- oy
);
666 static void resize_with_keys(gint keycode
, gint state
)
668 gint dw
= 0, dh
= 0, pdx
= 0, pdy
= 0, opx
, opy
, px
, py
;
669 gint dist
= 0, resist
= 0;
672 /* pick the edge if it needs to move */
673 if (keycode
== ob_keycode(OB_KEY_RIGHT
)) {
674 dir
= OB_DIRECTION_EAST
;
675 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
676 key_resize_edge
!= OB_DIRECTION_EAST
)
678 key_resize_edge
= OB_DIRECTION_EAST
;
682 if (keycode
== ob_keycode(OB_KEY_LEFT
)) {
683 dir
= OB_DIRECTION_WEST
;
684 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
685 key_resize_edge
!= OB_DIRECTION_EAST
)
687 key_resize_edge
= OB_DIRECTION_WEST
;
691 if (keycode
== ob_keycode(OB_KEY_UP
)) {
692 dir
= OB_DIRECTION_NORTH
;
693 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
694 key_resize_edge
!= OB_DIRECTION_SOUTH
)
696 key_resize_edge
= OB_DIRECTION_NORTH
;
700 if (keycode
== ob_keycode(OB_KEY_DOWN
)) {
701 dir
= OB_DIRECTION_SOUTH
;
702 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
703 key_resize_edge
!= OB_DIRECTION_SOUTH
)
705 key_resize_edge
= OB_DIRECTION_SOUTH
;
710 /* shift means jump to edge */
711 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
)) {
714 if (keycode
== ob_keycode(OB_KEY_RIGHT
))
715 dir
= OB_DIRECTION_EAST
;
716 else if (keycode
== ob_keycode(OB_KEY_LEFT
))
717 dir
= OB_DIRECTION_WEST
;
718 else if (keycode
== ob_keycode(OB_KEY_DOWN
))
719 dir
= OB_DIRECTION_SOUTH
;
720 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
721 dir
= OB_DIRECTION_NORTH
;
723 client_find_resize_directional(moveresize_client
, key_resize_edge
,
724 key_resize_edge
== dir
,
726 dw
= w
- moveresize_client
->area
.width
;
727 dh
= h
- moveresize_client
->area
.height
;
731 /* control means fine grained */
732 if (moveresize_client
->size_inc
.width
> 1) {
733 distw
= moveresize_client
->size_inc
.width
;
737 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
746 if (moveresize_client
->size_inc
.height
> 1) {
747 disth
= moveresize_client
->size_inc
.height
;
751 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
761 if (key_resize_edge
== OB_DIRECTION_WEST
) {
762 if (dir
== OB_DIRECTION_WEST
)
765 dw
= -(dist
= distw
);
767 else if (key_resize_edge
== OB_DIRECTION_EAST
) {
768 if (dir
== OB_DIRECTION_EAST
)
771 dw
= -(dist
= distw
);
773 else if (key_resize_edge
== OB_DIRECTION_NORTH
) {
774 if (dir
== OB_DIRECTION_NORTH
)
777 dh
= -(dist
= disth
);
779 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
780 if (dir
== OB_DIRECTION_SOUTH
)
783 dh
= -(dist
= disth
);
787 calc_resize(TRUE
, resist
, &dw
, &dh
, dir
);
788 if (key_resize_edge
== OB_DIRECTION_WEST
)
790 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
795 /* how to move the pointer to keep up with the change */
796 if (key_resize_edge
== OB_DIRECTION_WEST
)
798 else if (key_resize_edge
== OB_DIRECTION_EAST
)
800 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
802 else if (key_resize_edge
== OB_DIRECTION_SOUTH
)
805 screen_pointer_pos(&opx
, &opy
);
806 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, pdx
, pdy
);
807 /* steal the motion events this causes */
808 XSync(obt_display
, FALSE
);
811 while (XCheckTypedEvent(obt_display
, MotionNotify
, &ce
));
813 screen_pointer_pos(&px
, &py
);
817 /* because the cursor moves even though the window does
818 not nessesarily (resistance), this adjusts where the cursor
819 thinks it started so that it keeps up with where the window
821 start_x
+= (px
- opx
) - dw
;
822 start_y
+= (py
- opy
) - dh
;
826 gboolean
moveresize_event(XEvent
*e
)
828 gboolean used
= FALSE
;
830 if (!moveresize_in_progress
) return FALSE
;
832 if (e
->type
== ButtonPress
) {
834 start_x
= e
->xbutton
.x_root
;
835 start_y
= e
->xbutton
.y_root
;
836 button
= e
->xbutton
.button
; /* this will end it now */
838 used
= e
->xbutton
.button
== button
;
839 } else if (e
->type
== ButtonRelease
) {
840 if (!button
|| e
->xbutton
.button
== button
) {
841 moveresize_end(FALSE
);
844 } else if (e
->type
== MotionNotify
) {
846 cur_x
= start_cx
+ e
->xmotion
.x_root
- start_x
;
847 cur_y
= start_cy
+ e
->xmotion
.y_root
- start_y
;
849 do_edge_warp(e
->xmotion
.x_root
, e
->xmotion
.y_root
);
854 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
)) {
855 dw
= -(e
->xmotion
.x_root
- start_x
);
856 dh
= -(e
->xmotion
.y_root
- start_y
);
857 dir
= OB_DIRECTION_NORTHWEST
;
858 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
)) {
860 dh
= -(e
->xmotion
.y_root
- start_y
);
861 dir
= OB_DIRECTION_NORTH
;
863 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
)) {
864 dw
= (e
->xmotion
.x_root
- start_x
);
865 dh
= -(e
->xmotion
.y_root
- start_y
);
866 dir
= OB_DIRECTION_NORTHEAST
;
867 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT
)) {
868 dw
= (e
->xmotion
.x_root
- start_x
);
870 dir
= OB_DIRECTION_EAST
;
872 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
)) {
873 dw
= (e
->xmotion
.x_root
- start_x
);
874 dh
= (e
->xmotion
.y_root
- start_y
);
875 dir
= OB_DIRECTION_SOUTHEAST
;
876 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM
))
879 dh
= (e
->xmotion
.y_root
- start_y
);
880 dir
= OB_DIRECTION_SOUTH
;
882 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
)) {
883 dw
= -(e
->xmotion
.x_root
- start_x
);
884 dh
= (e
->xmotion
.y_root
- start_y
);
885 dir
= OB_DIRECTION_SOUTHWEST
;
886 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
)) {
887 dw
= -(e
->xmotion
.x_root
- start_x
);
889 dir
= OB_DIRECTION_WEST
;
891 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
892 dw
= (e
->xmotion
.x_root
- start_x
);
893 dh
= (e
->xmotion
.y_root
- start_y
);
894 dir
= OB_DIRECTION_SOUTHEAST
;
896 g_assert_not_reached();
898 dw
-= cur_w
- start_cw
;
899 dh
-= cur_h
- start_ch
;
901 calc_resize(FALSE
, 0, &dw
, &dh
, dir
);
905 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
906 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
) ||
907 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
))
911 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
912 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
) ||
913 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
))
921 } else if (e
->type
== KeyPress
) {
922 if (e
->xkey
.keycode
== ob_keycode(OB_KEY_ESCAPE
)) {
923 moveresize_end(TRUE
);
925 } else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RETURN
)) {
926 moveresize_end(FALSE
);
928 } else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RIGHT
) ||
929 e
->xkey
.keycode
== ob_keycode(OB_KEY_LEFT
) ||
930 e
->xkey
.keycode
== ob_keycode(OB_KEY_DOWN
) ||
931 e
->xkey
.keycode
== ob_keycode(OB_KEY_UP
))
933 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
934 resize_with_keys(e
->xkey
.keycode
, e
->xkey
.state
);
937 OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
))
939 move_with_keys(e
->xkey
.keycode
, e
->xkey
.state
);
945 else if (e
->type
== obt_display_extension_sync_basep
+ XSyncAlarmNotify
)
947 waiting_for_sync
= FALSE
; /* we got our sync... */
948 do_resize(); /* ...so try resize if there is more change pending */