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
);
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
)
373 if (config_resize_redraw
&& obt_display_extension_sync
&&
374 moveresize_client
->sync_request
&& moveresize_client
->sync_counter
&&
375 !moveresize_client
->not_responding
)
380 /* are we already waiting for the sync counter to catch up? */
381 if (waiting_for_sync
)
384 /* increment the value we're waiting for */
385 ++moveresize_client
->sync_counter_value
;
386 XSyncIntToValue(&val
, moveresize_client
->sync_counter_value
);
388 /* tell the client what we're waiting for */
389 ce
.xclient
.type
= ClientMessage
;
390 ce
.xclient
.message_type
= OBT_PROP_ATOM(WM_PROTOCOLS
);
391 ce
.xclient
.display
= obt_display
;
392 ce
.xclient
.window
= moveresize_client
->window
;
393 ce
.xclient
.format
= 32;
394 ce
.xclient
.data
.l
[0] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST
);
395 ce
.xclient
.data
.l
[1] = event_curtime
;
396 ce
.xclient
.data
.l
[2] = XSyncValueLow32(val
);
397 ce
.xclient
.data
.l
[3] = XSyncValueHigh32(val
);
398 ce
.xclient
.data
.l
[4] = 0l;
399 XSendEvent(obt_display
, moveresize_client
->window
, FALSE
,
402 waiting_for_sync
= TRUE
;
404 obt_main_loop_timeout_remove(ob_main_loop
, sync_timeout_func
);
405 obt_main_loop_timeout_add(ob_main_loop
, G_USEC_PER_SEC
* 2,
411 client_configure(moveresize_client
, cur_x
, cur_y
, cur_w
, cur_h
,
414 /* this would be better with a fixed width font ... XXX can do it better
415 if there are 2 text boxes */
416 if (config_resize_popup_show
== 2 || /* == "Always" */
417 (config_resize_popup_show
== 1 && /* == "Nonpixel" */
418 moveresize_client
->size_inc
.width
> 1 &&
419 moveresize_client
->size_inc
.height
> 1))
420 popup_coords(moveresize_client
, "%d x %d",
421 moveresize_client
->logical_size
.width
,
422 moveresize_client
->logical_size
.height
);
426 static gboolean
sync_timeout_func(gpointer data
)
428 waiting_for_sync
= FALSE
; /* we timed out waiting for our sync... */
429 do_resize(); /* ...so let any pending resizes through */
431 return FALSE
; /* don't repeat */
435 static void calc_resize(gboolean keyboard
, gint keydist
, gint
*dw
, gint
*dh
,
438 gint resist
, x
= 0, y
= 0, lw
, lh
, ow
, oh
, nw
, nh
;
447 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
450 case OB_DIRECTION_NORTH
:
451 case OB_DIRECTION_SOUTH
:
452 /* resize the width based on the height */
453 if (moveresize_client
->min_ratio
) {
454 if (nh
* moveresize_client
->min_ratio
> nw
)
455 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
457 if (moveresize_client
->max_ratio
) {
458 if (nh
* moveresize_client
->max_ratio
< nw
)
459 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
463 /* resize the height based on the width */
464 if (moveresize_client
->min_ratio
) {
465 if (nh
* moveresize_client
->min_ratio
> nw
)
466 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
468 if (moveresize_client
->max_ratio
) {
469 if (nh
* moveresize_client
->max_ratio
< nw
)
470 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
475 /* see its actual size (apply aspect ratios) */
476 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
,
482 /* resist_size_* needs the frame size */
483 nw
+= moveresize_client
->frame
->size
.left
+
484 moveresize_client
->frame
->size
.right
;
485 nh
+= moveresize_client
->frame
->size
.top
+
486 moveresize_client
->frame
->size
.bottom
;
488 if (keyboard
) resist
= keydist
- 1; /* resist for one key press */
489 else resist
= config_resist_win
;
490 resist_size_windows(moveresize_client
, resist
, &nw
, &nh
, dir
);
491 if (!keyboard
) resist
= config_resist_edge
;
492 resist_size_monitors(moveresize_client
, resist
, &nw
, &nh
, dir
);
494 nw
-= moveresize_client
->frame
->size
.left
+
495 moveresize_client
->frame
->size
.right
;
496 nh
-= moveresize_client
->frame
->size
.top
+
497 moveresize_client
->frame
->size
.bottom
;
502 /* take aspect ratios into account for resistance */
504 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
506 if (*dh
!= trydh
) { /* got resisted */
507 /* resize the width based on the height */
508 if (moveresize_client
->min_ratio
) {
509 if (nh
* moveresize_client
->min_ratio
> nw
)
510 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
512 if (moveresize_client
->max_ratio
) {
513 if (nh
* moveresize_client
->max_ratio
< nw
)
514 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
517 if (*dw
!= trydw
) { /* got resisted */
518 /* resize the height based on the width */
519 if (moveresize_client
->min_ratio
) {
520 if (nh
* moveresize_client
->min_ratio
> nw
)
521 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
523 if (moveresize_client
->max_ratio
) {
524 if (nh
* moveresize_client
->max_ratio
< nw
)
525 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
530 /* make sure it's all valid */
531 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
537 static gboolean
edge_warp_delay_func(gpointer data
)
541 /* only fire every second time. so it's fast the first time, but slower
544 d
= screen_find_desktop(screen_desktop
, edge_warp_dir
, TRUE
, FALSE
);
545 if (d
!= screen_desktop
) screen_set_desktop(d
, TRUE
);
547 edge_warp_odd
= !edge_warp_odd
;
549 return TRUE
; /* do repeat ! */
552 static void do_edge_warp(gint x
, gint y
)
557 if (!config_mouse_screenedgetime
) return;
561 for (i
= 0; i
< screen_num_monitors
; ++i
) {
562 Rect
*a
= screen_physical_area_monitor(i
);
563 if (x
== RECT_LEFT(*a
)) dir
= OB_DIRECTION_WEST
;
564 if (x
== RECT_RIGHT(*a
)) dir
= OB_DIRECTION_EAST
;
565 if (y
== RECT_TOP(*a
)) dir
= OB_DIRECTION_NORTH
;
566 if (y
== RECT_BOTTOM(*a
)) dir
= OB_DIRECTION_SOUTH
;
568 /* try check for xinerama boundaries */
569 if ((x
+ 1 == RECT_LEFT(*a
) || x
- 1 == RECT_RIGHT(*a
)) &&
570 (dir
== OB_DIRECTION_WEST
|| dir
== OB_DIRECTION_EAST
))
574 if ((y
+ 1 == RECT_TOP(*a
) || y
- 1 == RECT_BOTTOM(*a
)) &&
575 (dir
== OB_DIRECTION_NORTH
|| dir
== OB_DIRECTION_SOUTH
))
582 if (dir
!= edge_warp_dir
) {
584 if (dir
!= (ObDirection
)-1) {
585 edge_warp_odd
= TRUE
; /* switch on the first timeout */
586 obt_main_loop_timeout_add(ob_main_loop
,
587 config_mouse_screenedgetime
* 1000,
588 edge_warp_delay_func
,
595 static void cancel_edge_warp(void)
597 obt_main_loop_timeout_remove(ob_main_loop
, edge_warp_delay_func
);
600 static void move_with_keys(gint keycode
, gint state
)
602 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
603 gint opx
, px
, opy
, py
;
606 /* shift means jump to edge */
607 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
)) {
611 if (keycode
== ob_keycode(OB_KEY_RIGHT
))
612 dir
= OB_DIRECTION_EAST
;
613 else if (keycode
== ob_keycode(OB_KEY_LEFT
))
614 dir
= OB_DIRECTION_WEST
;
615 else if (keycode
== ob_keycode(OB_KEY_DOWN
))
616 dir
= OB_DIRECTION_SOUTH
;
617 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
618 dir
= OB_DIRECTION_NORTH
;
620 client_find_move_directional(moveresize_client
, dir
, &x
, &y
);
621 dx
= x
- moveresize_client
->area
.x
;
622 dy
= y
- moveresize_client
->area
.y
;
624 /* control means fine grained */
626 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
633 if (keycode
== ob_keycode(OB_KEY_RIGHT
))
635 else if (keycode
== ob_keycode(OB_KEY_LEFT
))
637 else if (keycode
== ob_keycode(OB_KEY_DOWN
))
639 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
643 screen_pointer_pos(&opx
, &opy
);
644 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
645 /* steal the motion events this causes */
646 XSync(obt_display
, FALSE
);
649 while (XCheckTypedEvent(obt_display
, MotionNotify
, &ce
));
651 screen_pointer_pos(&px
, &py
);
657 /* because the cursor moves even though the window does
658 not nessesarily (resistance), this adjusts where the curor
659 thinks it started so that it keeps up with where the window
661 start_x
+= (px
- opx
) - (cur_x
- ox
);
662 start_y
+= (py
- opy
) - (cur_y
- oy
);
665 static void resize_with_keys(gint keycode
, gint state
)
667 gint dw
= 0, dh
= 0, pdx
= 0, pdy
= 0, opx
, opy
, px
, py
;
668 gint dist
= 0, resist
= 0;
671 /* pick the edge if it needs to move */
672 if (keycode
== ob_keycode(OB_KEY_RIGHT
)) {
673 dir
= OB_DIRECTION_EAST
;
674 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
675 key_resize_edge
!= OB_DIRECTION_EAST
)
677 key_resize_edge
= OB_DIRECTION_EAST
;
681 if (keycode
== ob_keycode(OB_KEY_LEFT
)) {
682 dir
= OB_DIRECTION_WEST
;
683 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
684 key_resize_edge
!= OB_DIRECTION_EAST
)
686 key_resize_edge
= OB_DIRECTION_WEST
;
690 if (keycode
== ob_keycode(OB_KEY_UP
)) {
691 dir
= OB_DIRECTION_NORTH
;
692 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
693 key_resize_edge
!= OB_DIRECTION_SOUTH
)
695 key_resize_edge
= OB_DIRECTION_NORTH
;
699 if (keycode
== ob_keycode(OB_KEY_DOWN
)) {
700 dir
= OB_DIRECTION_SOUTH
;
701 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
702 key_resize_edge
!= OB_DIRECTION_SOUTH
)
704 key_resize_edge
= OB_DIRECTION_SOUTH
;
709 /* shift means jump to edge */
710 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
)) {
713 if (keycode
== ob_keycode(OB_KEY_RIGHT
))
714 dir
= OB_DIRECTION_EAST
;
715 else if (keycode
== ob_keycode(OB_KEY_LEFT
))
716 dir
= OB_DIRECTION_WEST
;
717 else if (keycode
== ob_keycode(OB_KEY_DOWN
))
718 dir
= OB_DIRECTION_SOUTH
;
719 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
720 dir
= OB_DIRECTION_NORTH
;
722 client_find_resize_directional(moveresize_client
, key_resize_edge
,
723 key_resize_edge
== dir
,
725 dw
= w
- moveresize_client
->area
.width
;
726 dh
= h
- moveresize_client
->area
.height
;
730 /* control means fine grained */
731 if (moveresize_client
->size_inc
.width
> 1) {
732 distw
= moveresize_client
->size_inc
.width
;
736 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
745 if (moveresize_client
->size_inc
.height
> 1) {
746 disth
= moveresize_client
->size_inc
.height
;
750 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
760 if (key_resize_edge
== OB_DIRECTION_WEST
) {
761 if (dir
== OB_DIRECTION_WEST
)
764 dw
= -(dist
= distw
);
766 else if (key_resize_edge
== OB_DIRECTION_EAST
) {
767 if (dir
== OB_DIRECTION_EAST
)
770 dw
= -(dist
= distw
);
772 else if (key_resize_edge
== OB_DIRECTION_NORTH
) {
773 if (dir
== OB_DIRECTION_NORTH
)
776 dh
= -(dist
= disth
);
778 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
779 if (dir
== OB_DIRECTION_SOUTH
)
782 dh
= -(dist
= disth
);
786 calc_resize(TRUE
, resist
, &dw
, &dh
, dir
);
787 if (key_resize_edge
== OB_DIRECTION_WEST
)
789 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
794 /* how to move the pointer to keep up with the change */
795 if (key_resize_edge
== OB_DIRECTION_WEST
)
797 else if (key_resize_edge
== OB_DIRECTION_EAST
)
799 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
801 else if (key_resize_edge
== OB_DIRECTION_SOUTH
)
804 screen_pointer_pos(&opx
, &opy
);
805 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, pdx
, pdy
);
806 /* steal the motion events this causes */
807 XSync(obt_display
, FALSE
);
810 while (XCheckTypedEvent(obt_display
, MotionNotify
, &ce
));
812 screen_pointer_pos(&px
, &py
);
816 /* because the cursor moves even though the window does
817 not nessesarily (resistance), this adjusts where the cursor
818 thinks it started so that it keeps up with where the window
820 start_x
+= (px
- opx
) - dw
;
821 start_y
+= (py
- opy
) - dh
;
825 gboolean
moveresize_event(XEvent
*e
)
827 gboolean used
= FALSE
;
829 if (!moveresize_in_progress
) return FALSE
;
831 if (e
->type
== ButtonPress
) {
833 start_x
= e
->xbutton
.x_root
;
834 start_y
= e
->xbutton
.y_root
;
835 button
= e
->xbutton
.button
; /* this will end it now */
837 used
= e
->xbutton
.button
== button
;
838 } else if (e
->type
== ButtonRelease
) {
839 if (!button
|| e
->xbutton
.button
== button
) {
840 moveresize_end(FALSE
);
843 } else if (e
->type
== MotionNotify
) {
845 cur_x
= start_cx
+ e
->xmotion
.x_root
- start_x
;
846 cur_y
= start_cy
+ e
->xmotion
.y_root
- start_y
;
848 do_edge_warp(e
->xmotion
.x_root
, e
->xmotion
.y_root
);
853 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
)) {
854 dw
= -(e
->xmotion
.x_root
- start_x
);
855 dh
= -(e
->xmotion
.y_root
- start_y
);
856 dir
= OB_DIRECTION_NORTHWEST
;
857 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
)) {
859 dh
= -(e
->xmotion
.y_root
- start_y
);
860 dir
= OB_DIRECTION_NORTH
;
862 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
)) {
863 dw
= (e
->xmotion
.x_root
- start_x
);
864 dh
= -(e
->xmotion
.y_root
- start_y
);
865 dir
= OB_DIRECTION_NORTHEAST
;
866 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT
)) {
867 dw
= (e
->xmotion
.x_root
- start_x
);
869 dir
= OB_DIRECTION_EAST
;
871 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
)) {
872 dw
= (e
->xmotion
.x_root
- start_x
);
873 dh
= (e
->xmotion
.y_root
- start_y
);
874 dir
= OB_DIRECTION_SOUTHEAST
;
875 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM
))
878 dh
= (e
->xmotion
.y_root
- start_y
);
879 dir
= OB_DIRECTION_SOUTH
;
881 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
)) {
882 dw
= -(e
->xmotion
.x_root
- start_x
);
883 dh
= (e
->xmotion
.y_root
- start_y
);
884 dir
= OB_DIRECTION_SOUTHWEST
;
885 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
)) {
886 dw
= -(e
->xmotion
.x_root
- start_x
);
888 dir
= OB_DIRECTION_WEST
;
890 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
891 dw
= (e
->xmotion
.x_root
- start_x
);
892 dh
= (e
->xmotion
.y_root
- start_y
);
893 dir
= OB_DIRECTION_SOUTHEAST
;
895 g_assert_not_reached();
897 dw
-= cur_w
- start_cw
;
898 dh
-= cur_h
- start_ch
;
900 calc_resize(FALSE
, 0, &dw
, &dh
, dir
);
904 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
905 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
) ||
906 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
))
910 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
911 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
) ||
912 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
))
920 } else if (e
->type
== KeyPress
) {
921 if (e
->xkey
.keycode
== ob_keycode(OB_KEY_ESCAPE
)) {
922 moveresize_end(TRUE
);
924 } else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RETURN
)) {
925 moveresize_end(FALSE
);
927 } else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RIGHT
) ||
928 e
->xkey
.keycode
== ob_keycode(OB_KEY_LEFT
) ||
929 e
->xkey
.keycode
== ob_keycode(OB_KEY_DOWN
) ||
930 e
->xkey
.keycode
== ob_keycode(OB_KEY_UP
))
932 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
933 resize_with_keys(e
->xkey
.keycode
, e
->xkey
.state
);
936 OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
))
938 move_with_keys(e
->xkey
.keycode
, e
->xkey
.state
);
944 else if (e
->type
== obt_display_extension_sync_basep
+ XSyncAlarmNotify
)
946 waiting_for_sync
= FALSE
; /* we got our sync... */
947 do_resize(); /* ...so try resize if there is more change pending */