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"
35 #include "obt/xqueue.h"
37 #include "obt/keyboard.h"
42 /* how far windows move and resize with the keyboard arrows */
44 #define SYNC_TIMEOUTS 4
46 gboolean moveresize_in_progress
= FALSE
;
47 ObClient
*moveresize_client
= NULL
;
49 XSyncAlarm moveresize_alarm
= None
;
52 static gboolean moving
= FALSE
; /* TRUE - moving, FALSE - resizing */
54 static gint start_x
, start_y
, start_cx
, start_cy
, start_cw
, start_ch
;
55 static gint cur_x
, cur_y
, cur_w
, cur_h
;
57 static guint32 corner
;
58 static ObDirection edge_warp_dir
= -1;
59 static gboolean edge_warp_odd
= FALSE
;
60 static ObDirection key_resize_edge
= -1;
62 static guint waiting_for_sync
;
65 static ObPopup
*popup
= NULL
;
67 static void do_move(gboolean keyboard
, gint keydist
);
68 static void do_resize(void);
69 static void do_edge_warp(gint x
, gint y
);
70 static void cancel_edge_warp();
72 static gboolean
sync_timeout_func(gpointer data
);
75 static void client_dest(ObClient
*client
, gpointer data
)
77 if (moveresize_client
== client
)
81 void moveresize_startup(gboolean reconfig
)
84 popup_set_text_align(popup
, RR_JUSTIFY_CENTER
);
87 client_add_destroy_notify(client_dest
, NULL
);
90 void moveresize_shutdown(gboolean reconfig
)
93 if (moveresize_in_progress
)
94 moveresize_end(FALSE
);
95 client_remove_destroy_notify(client_dest
);
102 static void popup_coords(ObClient
*c
, const gchar
*format
, gint a
, gint b
)
106 text
= g_strdup_printf(format
, a
, b
);
107 if (config_resize_popup_pos
== OB_RESIZE_POS_TOP
)
108 popup_position(popup
, SouthGravity
,
110 + c
->frame
->area
.width
/2,
111 c
->frame
->area
.y
- ob_rr_theme
->fbwidth
);
112 else if (config_resize_popup_pos
== OB_RESIZE_POS_CENTER
)
113 popup_position(popup
, CenterGravity
,
114 c
->frame
->area
.x
+ c
->frame
->area
.width
/ 2,
115 c
->frame
->area
.y
+ c
->frame
->area
.height
/ 2);
117 const Rect
*area
= screen_physical_area_active();
120 x
= config_resize_popup_fixed
.x
.pos
;
121 if (config_resize_popup_fixed
.x
.center
)
122 x
= area
->x
+ area
->width
/2;
123 else if (config_resize_popup_fixed
.x
.opposite
)
124 x
= RECT_RIGHT(*area
) - x
;
128 y
= config_resize_popup_fixed
.y
.pos
;
129 if (config_resize_popup_fixed
.y
.center
)
130 y
= area
->y
+ area
->height
/2;
131 else if (config_resize_popup_fixed
.y
.opposite
)
132 y
= RECT_RIGHT(*area
) - y
;
136 if (config_resize_popup_fixed
.x
.center
) {
137 if (config_resize_popup_fixed
.y
.center
)
138 gravity
= CenterGravity
;
139 else if (config_resize_popup_fixed
.y
.opposite
)
140 gravity
= SouthGravity
;
142 gravity
= NorthGravity
;
144 else if (config_resize_popup_fixed
.x
.opposite
) {
145 if (config_resize_popup_fixed
.y
.center
)
146 gravity
= EastGravity
;
147 else if (config_resize_popup_fixed
.y
.opposite
)
148 gravity
= SouthEastGravity
;
150 gravity
= NorthEastGravity
;
153 if (config_resize_popup_fixed
.y
.center
)
154 gravity
= WestGravity
;
155 else if (config_resize_popup_fixed
.y
.opposite
)
156 gravity
= SouthWestGravity
;
158 gravity
= NorthWestGravity
;
161 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
= 0;
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
360 USE cur_x AND cur_y HERE ! Otherwise the try_configure won't know
361 what struts to use !!
367 client_try_configure(moveresize_client
, &x
, &y
, &w
, &h
,
369 if (!(w
== moveresize_client
->area
.width
&&
370 h
== moveresize_client
->area
.height
) &&
371 /* if waiting_for_sync == 0, then we aren't waiting.
372 if it is > SYNC_TIMEOUTS, then we have timed out
373 that many times already, so forget about waiting more */
374 (waiting_for_sync
== 0 || waiting_for_sync
> SYNC_TIMEOUTS
))
377 if (config_resize_redraw
&& obt_display_extension_sync
&&
378 /* don't send another sync when one is pending */
379 waiting_for_sync
== 0 &&
380 moveresize_client
->sync_request
&&
381 moveresize_client
->sync_counter
&&
382 !moveresize_client
->not_responding
)
387 /* increment the value we're waiting for */
388 ++moveresize_client
->sync_counter_value
;
389 XSyncIntToValue(&val
, moveresize_client
->sync_counter_value
);
391 /* tell the client what we're waiting for */
392 ce
.xclient
.type
= ClientMessage
;
393 ce
.xclient
.message_type
= OBT_PROP_ATOM(WM_PROTOCOLS
);
394 ce
.xclient
.display
= obt_display
;
395 ce
.xclient
.window
= moveresize_client
->window
;
396 ce
.xclient
.format
= 32;
397 ce
.xclient
.data
.l
[0] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST
);
398 ce
.xclient
.data
.l
[1] = event_time();
399 ce
.xclient
.data
.l
[2] = XSyncValueLow32(val
);
400 ce
.xclient
.data
.l
[3] = XSyncValueHigh32(val
);
401 ce
.xclient
.data
.l
[4] = 0l;
402 XSendEvent(obt_display
, moveresize_client
->window
, FALSE
,
405 waiting_for_sync
= 1;
407 obt_main_loop_timeout_remove(ob_main_loop
, sync_timeout_func
);
408 obt_main_loop_timeout_add(ob_main_loop
, G_USEC_PER_SEC
* 2,
414 /* force a ConfigureNotify, it is part of the spec for SYNC resizing
415 and MUST follow the sync counter notification */
416 client_configure(moveresize_client
, cur_x
, cur_y
, cur_w
, cur_h
,
420 /* this would be better with a fixed width font ... XXX can do it better
421 if there are 2 text boxes */
422 if (config_resize_popup_show
== 2 || /* == "Always" */
423 (config_resize_popup_show
== 1 && /* == "Nonpixel" */
424 moveresize_client
->size_inc
.width
> 1 &&
425 moveresize_client
->size_inc
.height
> 1))
426 popup_coords(moveresize_client
, "%d x %d", lw
, lh
);
430 static gboolean
sync_timeout_func(gpointer data
)
432 ++waiting_for_sync
; /* we timed out waiting for our sync... */
433 do_resize(); /* ...so let any pending resizes through */
435 if (waiting_for_sync
> SYNC_TIMEOUTS
)
436 return FALSE
; /* don't repeat */
438 return TRUE
; /* keep waiting */
442 static void calc_resize(gboolean keyboard
, gint keydist
, gint
*dw
, gint
*dh
,
445 gint resist
, x
= 0, y
= 0, lw
, lh
, ow
, oh
, nw
, nh
;
454 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
457 case OB_DIRECTION_NORTH
:
458 case OB_DIRECTION_SOUTH
:
459 /* resize the width based on the height */
460 if (moveresize_client
->min_ratio
) {
461 if (nh
* moveresize_client
->min_ratio
> nw
)
462 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
464 if (moveresize_client
->max_ratio
) {
465 if (nh
* moveresize_client
->max_ratio
< nw
)
466 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
470 /* resize the height based on the width */
471 if (moveresize_client
->min_ratio
) {
472 if (nh
* moveresize_client
->min_ratio
> nw
)
473 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
475 if (moveresize_client
->max_ratio
) {
476 if (nh
* moveresize_client
->max_ratio
< nw
)
477 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
482 /* see its actual size (apply aspect ratios) */
483 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
,
489 /* resist_size_* needs the frame size */
490 nw
+= moveresize_client
->frame
->size
.left
+
491 moveresize_client
->frame
->size
.right
;
492 nh
+= moveresize_client
->frame
->size
.top
+
493 moveresize_client
->frame
->size
.bottom
;
495 if (keyboard
) resist
= keydist
- 1; /* resist for one key press */
496 else resist
= config_resist_win
;
497 resist_size_windows(moveresize_client
, resist
, &nw
, &nh
, dir
);
498 if (!keyboard
) resist
= config_resist_edge
;
499 resist_size_monitors(moveresize_client
, resist
, &nw
, &nh
, dir
);
501 nw
-= moveresize_client
->frame
->size
.left
+
502 moveresize_client
->frame
->size
.right
;
503 nh
-= moveresize_client
->frame
->size
.top
+
504 moveresize_client
->frame
->size
.bottom
;
509 /* take aspect ratios into account for resistance */
511 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
513 if (*dh
!= trydh
) { /* got resisted */
514 /* resize the width based on the height */
515 if (moveresize_client
->min_ratio
) {
516 if (nh
* moveresize_client
->min_ratio
> nw
)
517 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
519 if (moveresize_client
->max_ratio
) {
520 if (nh
* moveresize_client
->max_ratio
< nw
)
521 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
524 if (*dw
!= trydw
) { /* got resisted */
525 /* resize the height based on the width */
526 if (moveresize_client
->min_ratio
) {
527 if (nh
* moveresize_client
->min_ratio
> nw
)
528 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
530 if (moveresize_client
->max_ratio
) {
531 if (nh
* moveresize_client
->max_ratio
< nw
)
532 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
537 /* make sure it's all valid */
538 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
544 static void edge_warp_move_ptr(void)
549 screen_pointer_pos(&x
, &y
);
550 a
= screen_physical_area_all_monitors();
552 switch (edge_warp_dir
) {
553 case OB_DIRECTION_NORTH
:
556 case OB_DIRECTION_EAST
:
559 case OB_DIRECTION_SOUTH
:
562 case OB_DIRECTION_WEST
:
566 g_assert_not_reached();
569 XWarpPointer(obt_display
, 0, obt_root(ob_screen
), 0, 0, 0, 0, x
, y
);
572 static gboolean
edge_warp_delay_func(gpointer data
)
576 /* only fire every second time. so it's fast the first time, but slower
579 d
= screen_find_desktop(screen_desktop
, edge_warp_dir
, TRUE
, FALSE
);
580 if (d
!= screen_desktop
) {
581 if (config_mouse_screenedgewarp
) edge_warp_move_ptr();
582 screen_set_desktop(d
, TRUE
);
585 edge_warp_odd
= !edge_warp_odd
;
587 return TRUE
; /* do repeat ! */
590 static void do_edge_warp(gint x
, gint y
)
595 if (!config_mouse_screenedgetime
) return;
599 for (i
= 0; i
< screen_num_monitors
; ++i
) {
600 const Rect
*a
= screen_physical_area_monitor(i
);
601 if (x
== RECT_LEFT(*a
)) dir
= OB_DIRECTION_WEST
;
602 if (x
== RECT_RIGHT(*a
)) dir
= OB_DIRECTION_EAST
;
603 if (y
== RECT_TOP(*a
)) dir
= OB_DIRECTION_NORTH
;
604 if (y
== RECT_BOTTOM(*a
)) dir
= OB_DIRECTION_SOUTH
;
606 /* try check for xinerama boundaries */
607 if ((x
+ 1 == RECT_LEFT(*a
) || x
- 1 == RECT_RIGHT(*a
)) &&
608 (dir
== OB_DIRECTION_WEST
|| dir
== OB_DIRECTION_EAST
))
612 if ((y
+ 1 == RECT_TOP(*a
) || y
- 1 == RECT_BOTTOM(*a
)) &&
613 (dir
== OB_DIRECTION_NORTH
|| dir
== OB_DIRECTION_SOUTH
))
619 if (dir
!= edge_warp_dir
) {
621 if (dir
!= (ObDirection
)-1) {
622 edge_warp_odd
= TRUE
; /* switch on the first timeout */
623 obt_main_loop_timeout_add(ob_main_loop
,
624 config_mouse_screenedgetime
* 1000,
625 edge_warp_delay_func
,
632 static void cancel_edge_warp(void)
634 obt_main_loop_timeout_remove(ob_main_loop
, edge_warp_delay_func
);
637 static void move_with_keys(KeySym sym
, guint state
)
639 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
640 gint opx
, px
, opy
, py
;
643 /* shift means jump to edge */
644 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
))
650 dir
= OB_DIRECTION_EAST
;
651 else if (sym
== XK_Left
)
652 dir
= OB_DIRECTION_WEST
;
653 else if (sym
== XK_Down
)
654 dir
= OB_DIRECTION_SOUTH
;
655 else /* sym == XK_Up */
656 dir
= OB_DIRECTION_NORTH
;
658 client_find_move_directional(moveresize_client
, dir
, &x
, &y
);
659 dx
= x
- moveresize_client
->area
.x
;
660 dy
= y
- moveresize_client
->area
.y
;
662 /* control means fine grained */
664 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
673 else if (sym
== XK_Left
)
675 else if (sym
== XK_Down
)
677 else /* if (sym == XK_Up) */
681 screen_pointer_pos(&opx
, &opy
);
682 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
683 /* steal the motion events this causes */
684 XSync(obt_display
, FALSE
);
687 while (xqueue_remove_local(&ce
, xqueue_match_type
,
688 GINT_TO_POINTER(MotionNotify
)));
690 screen_pointer_pos(&px
, &py
);
696 /* because the cursor moves even though the window does
697 not nessesarily (resistance), this adjusts where the curor
698 thinks it started so that it keeps up with where the window
700 start_x
+= (px
- opx
) - (cur_x
- ox
);
701 start_y
+= (py
- opy
) - (cur_y
- oy
);
704 static void resize_with_keys(KeySym sym
, guint state
)
706 gint dw
= 0, dh
= 0, pdx
= 0, pdy
= 0, opx
, opy
, px
, py
;
710 /* pick the edge if it needs to move */
711 if (sym
== XK_Right
) {
712 dir
= OB_DIRECTION_EAST
;
713 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
714 key_resize_edge
!= OB_DIRECTION_EAST
)
716 key_resize_edge
= OB_DIRECTION_EAST
;
719 } else if (sym
== XK_Left
) {
720 dir
= OB_DIRECTION_WEST
;
721 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
722 key_resize_edge
!= OB_DIRECTION_EAST
)
724 key_resize_edge
= OB_DIRECTION_WEST
;
727 } else if (sym
== XK_Up
) {
728 dir
= OB_DIRECTION_NORTH
;
729 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
730 key_resize_edge
!= OB_DIRECTION_SOUTH
)
732 key_resize_edge
= OB_DIRECTION_NORTH
;
735 } else /* if (sym == XK_Down) */ {
736 dir
= OB_DIRECTION_SOUTH
;
737 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
738 key_resize_edge
!= OB_DIRECTION_SOUTH
)
740 key_resize_edge
= OB_DIRECTION_SOUTH
;
745 /* shift means jump to edge */
746 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
))
751 dir
= OB_DIRECTION_EAST
;
752 else if (sym
== XK_Left
)
753 dir
= OB_DIRECTION_WEST
;
754 else if (sym
== XK_Down
)
755 dir
= OB_DIRECTION_SOUTH
;
756 else /* if (sym == XK_Up)) */
757 dir
= OB_DIRECTION_NORTH
;
759 client_find_resize_directional(moveresize_client
, key_resize_edge
,
760 key_resize_edge
== dir
,
762 dw
= w
- moveresize_client
->area
.width
;
763 dh
= h
- moveresize_client
->area
.height
;
767 /* control means fine grained */
768 if (moveresize_client
->size_inc
.width
> 1) {
769 distw
= moveresize_client
->size_inc
.width
;
773 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
782 if (moveresize_client
->size_inc
.height
> 1) {
783 disth
= moveresize_client
->size_inc
.height
;
787 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
797 if (key_resize_edge
== OB_DIRECTION_WEST
) {
798 if (dir
== OB_DIRECTION_WEST
)
803 else if (key_resize_edge
== OB_DIRECTION_EAST
) {
804 if (dir
== OB_DIRECTION_EAST
)
809 else if (key_resize_edge
== OB_DIRECTION_NORTH
) {
810 if (dir
== OB_DIRECTION_NORTH
)
815 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
816 if (dir
== OB_DIRECTION_SOUTH
)
823 calc_resize(TRUE
, resist
, &dw
, &dh
, dir
);
824 if (key_resize_edge
== OB_DIRECTION_WEST
)
826 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
831 /* how to move the pointer to keep up with the change */
832 if (key_resize_edge
== OB_DIRECTION_WEST
)
834 else if (key_resize_edge
== OB_DIRECTION_EAST
)
836 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
838 else if (key_resize_edge
== OB_DIRECTION_SOUTH
)
841 screen_pointer_pos(&opx
, &opy
);
842 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, pdx
, pdy
);
843 /* steal the motion events this causes */
844 XSync(obt_display
, FALSE
);
847 while (xqueue_remove_local(&ce
, xqueue_match_type
,
848 GINT_TO_POINTER(MotionNotify
)));
850 screen_pointer_pos(&px
, &py
);
854 /* because the cursor moves even though the window does
855 not nessesarily (resistance), this adjusts where the cursor
856 thinks it started so that it keeps up with where the window
858 start_x
+= (px
- opx
) - dw
;
859 start_y
+= (py
- opy
) - dh
;
863 gboolean
moveresize_event(XEvent
*e
)
865 gboolean used
= FALSE
;
867 if (!moveresize_in_progress
) return FALSE
;
869 if (e
->type
== ButtonPress
) {
871 start_x
= e
->xbutton
.x_root
;
872 start_y
= e
->xbutton
.y_root
;
873 button
= e
->xbutton
.button
; /* this will end it now */
875 used
= e
->xbutton
.button
== button
;
876 } else if (e
->type
== ButtonRelease
) {
877 if (!button
|| e
->xbutton
.button
== button
) {
878 moveresize_end(FALSE
);
881 } else if (e
->type
== MotionNotify
) {
883 cur_x
= start_cx
+ e
->xmotion
.x_root
- start_x
;
884 cur_y
= start_cy
+ e
->xmotion
.y_root
- start_y
;
886 do_edge_warp(e
->xmotion
.x_root
, e
->xmotion
.y_root
);
891 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
)) {
892 dw
= -(e
->xmotion
.x_root
- start_x
);
893 dh
= -(e
->xmotion
.y_root
- start_y
);
894 dir
= OB_DIRECTION_NORTHWEST
;
895 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
)) {
897 dh
= -(e
->xmotion
.y_root
- start_y
);
898 dir
= OB_DIRECTION_NORTH
;
900 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
)) {
901 dw
= (e
->xmotion
.x_root
- start_x
);
902 dh
= -(e
->xmotion
.y_root
- start_y
);
903 dir
= OB_DIRECTION_NORTHEAST
;
904 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT
)) {
905 dw
= (e
->xmotion
.x_root
- start_x
);
907 dir
= OB_DIRECTION_EAST
;
909 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
)) {
910 dw
= (e
->xmotion
.x_root
- start_x
);
911 dh
= (e
->xmotion
.y_root
- start_y
);
912 dir
= OB_DIRECTION_SOUTHEAST
;
913 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM
))
916 dh
= (e
->xmotion
.y_root
- start_y
);
917 dir
= OB_DIRECTION_SOUTH
;
919 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
)) {
920 dw
= -(e
->xmotion
.x_root
- start_x
);
921 dh
= (e
->xmotion
.y_root
- start_y
);
922 dir
= OB_DIRECTION_SOUTHWEST
;
923 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
)) {
924 dw
= -(e
->xmotion
.x_root
- start_x
);
926 dir
= OB_DIRECTION_WEST
;
928 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
929 dw
= (e
->xmotion
.x_root
- start_x
);
930 dh
= (e
->xmotion
.y_root
- start_y
);
931 dir
= OB_DIRECTION_SOUTHEAST
;
933 g_assert_not_reached();
935 dw
-= cur_w
- start_cw
;
936 dh
-= cur_h
- start_ch
;
938 calc_resize(FALSE
, 0, &dw
, &dh
, dir
);
942 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
943 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
) ||
944 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
))
948 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
949 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
) ||
950 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
))
958 } else if (e
->type
== KeyPress
) {
959 KeySym sym
= obt_keyboard_keypress_to_keysym(e
);
961 if (sym
== XK_Escape
) {
962 moveresize_end(TRUE
);
964 } else if (sym
== XK_Return
|| sym
== XK_KP_Enter
) {
965 moveresize_end(FALSE
);
967 } else if (sym
== XK_Right
|| sym
== XK_Left
||
968 sym
== XK_Up
|| sym
== XK_Down
)
970 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
971 resize_with_keys(sym
, e
->xkey
.state
);
974 OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
))
976 move_with_keys(sym
, e
->xkey
.state
);
982 else if (e
->type
== obt_display_extension_sync_basep
+ XSyncAlarmNotify
)
984 waiting_for_sync
= 0; /* we got our sync... */
985 do_resize(); /* ...so try resize if there is more change pending */