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 */
45 gboolean moveresize_in_progress
= FALSE
;
46 ObClient
*moveresize_client
= NULL
;
48 XSyncAlarm moveresize_alarm
= None
;
51 static gboolean moving
= FALSE
; /* TRUE - moving, FALSE - resizing */
53 static gint start_x
, start_y
, start_cx
, start_cy
, start_cw
, start_ch
;
54 static gint cur_x
, cur_y
, cur_w
, cur_h
;
56 static guint32 corner
;
57 static ObDirection edge_warp_dir
= -1;
58 static gboolean edge_warp_odd
= FALSE
;
59 static ObDirection key_resize_edge
= -1;
61 static gboolean waiting_for_sync
;
64 static ObPopup
*popup
= NULL
;
66 static void do_move(gboolean keyboard
, gint keydist
);
67 static void do_resize(void);
68 static void do_edge_warp(gint x
, gint y
);
69 static void cancel_edge_warp();
71 static gboolean
sync_timeout_func(gpointer data
);
74 static void client_dest(ObClient
*client
, gpointer data
)
76 if (moveresize_client
== client
)
80 void moveresize_startup(gboolean reconfig
)
83 popup_set_text_align(popup
, RR_JUSTIFY_CENTER
);
86 client_add_destroy_notify(client_dest
, NULL
);
89 void moveresize_shutdown(gboolean reconfig
)
92 if (moveresize_in_progress
)
93 moveresize_end(FALSE
);
94 client_remove_destroy_notify(client_dest
);
101 static void popup_coords(ObClient
*c
, const gchar
*format
, gint a
, gint b
)
105 text
= g_strdup_printf(format
, a
, b
);
106 if (config_resize_popup_pos
== OB_RESIZE_POS_TOP
)
107 popup_position(popup
, SouthGravity
,
109 + c
->frame
->area
.width
/2,
110 c
->frame
->area
.y
- ob_rr_theme
->fbwidth
);
111 else if (config_resize_popup_pos
== OB_RESIZE_POS_CENTER
)
112 popup_position(popup
, CenterGravity
,
113 c
->frame
->area
.x
+ c
->frame
->area
.width
/ 2,
114 c
->frame
->area
.y
+ c
->frame
->area
.height
/ 2);
116 const Rect
*area
= screen_physical_area_active();
119 x
= config_resize_popup_fixed
.x
.pos
;
120 if (config_resize_popup_fixed
.x
.center
)
121 x
= area
->x
+ area
->width
/2;
122 else if (config_resize_popup_fixed
.x
.opposite
)
123 x
= RECT_RIGHT(*area
) - x
;
127 y
= config_resize_popup_fixed
.y
.pos
;
128 if (config_resize_popup_fixed
.y
.center
)
129 y
= area
->y
+ area
->height
/2;
130 else if (config_resize_popup_fixed
.y
.opposite
)
131 y
= RECT_RIGHT(*area
) - y
;
135 if (config_resize_popup_fixed
.x
.center
) {
136 if (config_resize_popup_fixed
.y
.center
)
137 gravity
= CenterGravity
;
138 else if (config_resize_popup_fixed
.y
.opposite
)
139 gravity
= SouthGravity
;
141 gravity
= NorthGravity
;
143 else if (config_resize_popup_fixed
.x
.opposite
) {
144 if (config_resize_popup_fixed
.y
.center
)
145 gravity
= EastGravity
;
146 else if (config_resize_popup_fixed
.y
.opposite
)
147 gravity
= SouthEastGravity
;
149 gravity
= NorthEastGravity
;
152 if (config_resize_popup_fixed
.y
.center
)
153 gravity
= WestGravity
;
154 else if (config_resize_popup_fixed
.y
.opposite
)
155 gravity
= SouthWestGravity
;
157 gravity
= NorthWestGravity
;
160 popup_position(popup
, gravity
, x
, y
);
162 popup_show(popup
, text
);
166 void moveresize_start(ObClient
*c
, gint x
, gint y
, guint b
, guint32 cnr
)
169 gboolean mv
= (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE
) ||
170 cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
));
174 if (moveresize_in_progress
|| !c
->frame
->visible
||
176 (c
->functions
& OB_CLIENT_FUNC_MOVE
) :
177 (c
->functions
& OB_CLIENT_FUNC_RESIZE
)))
180 if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
)) {
181 cur
= OB_CURSOR_NORTHWEST
;
184 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
)) {
185 cur
= OB_CURSOR_NORTH
;
188 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
)) {
189 cur
= OB_CURSOR_NORTHEAST
;
192 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT
))
193 cur
= OB_CURSOR_EAST
;
194 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
))
195 cur
= OB_CURSOR_SOUTHEAST
;
196 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM
))
197 cur
= OB_CURSOR_SOUTH
;
198 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
)) {
199 cur
= OB_CURSOR_SOUTHWEST
;
202 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
)) {
203 cur
= OB_CURSOR_WEST
;
206 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
))
207 cur
= OB_CURSOR_SOUTHEAST
;
208 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE
))
209 cur
= OB_CURSOR_MOVE
;
210 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
))
211 cur
= OB_CURSOR_MOVE
;
213 g_assert_not_reached();
215 /* keep the pointer bounded to the screen for move/resize */
216 if (!grab_pointer(FALSE
, TRUE
, cur
))
218 if (!grab_keyboard()) {
223 frame_end_iconify_animation(c
->frame
);
226 moveresize_client
= c
;
227 start_cx
= c
->area
.x
;
228 start_cy
= c
->area
.y
;
229 start_cw
= c
->area
.width
;
230 start_ch
= c
->area
.height
;
231 /* these adjustments for the size_inc make resizing a terminal more
232 friendly. you essentially start the resize in the middle of the
233 increment instead of at 0, so you have to move half an increment
234 either way instead of a full increment one and 1 px the other. */
235 start_x
= x
- (mv
? 0 : left
* c
->size_inc
.width
/ 2);
236 start_y
= y
- (mv
? 0 : up
* c
->size_inc
.height
/ 2);
239 key_resize_edge
= -1;
242 have to change start_cx and start_cy if going to do this..
243 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
244 corner == prop_atoms.net_wm_moveresize_size_keyboard)
245 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
246 c->area.width / 2, c->area.height / 2);
254 moveresize_in_progress
= TRUE
;
257 if (config_resize_redraw
&& !moving
&& obt_display_extension_sync
&&
258 moveresize_client
->sync_request
&& moveresize_client
->sync_counter
&&
259 !moveresize_client
->not_responding
)
261 /* Initialize values for the resize syncing, and create an alarm for
262 the client's xsync counter */
265 XSyncAlarmAttributes aa
;
267 /* set the counter to an initial value */
268 XSyncIntToValue(&val
, 0);
269 XSyncSetCounter(obt_display
, moveresize_client
->sync_counter
, val
);
271 /* this will be incremented when we tell the client what we're
273 moveresize_client
->sync_counter_value
= 0;
275 /* the next sequence we're waiting for with the alarm */
276 XSyncIntToValue(&val
, 1);
278 /* set an alarm on the counter */
279 aa
.trigger
.counter
= moveresize_client
->sync_counter
;
280 aa
.trigger
.wait_value
= val
;
281 aa
.trigger
.value_type
= XSyncAbsolute
;
282 aa
.trigger
.test_type
= XSyncPositiveTransition
;
284 XSyncIntToValue(&aa
.delta
, 1);
285 moveresize_alarm
= XSyncCreateAlarm(obt_display
,
294 waiting_for_sync
= FALSE
;
299 void moveresize_end(gboolean cancel
)
308 /* turn off the alarm */
309 if (moveresize_alarm
!= None
) {
310 XSyncDestroyAlarm(obt_display
, moveresize_alarm
);
311 moveresize_alarm
= None
;
314 obt_main_loop_timeout_remove(ob_main_loop
, sync_timeout_func
);
318 /* don't use client_move() here, use the same width/height as
319 we've been using during the move, otherwise we get different results
320 when moving maximized windows between monitors of different sizes !
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
),
329 /* dont edge warp after its ended */
332 moveresize_in_progress
= FALSE
;
333 moveresize_client
= NULL
;
336 static void do_move(gboolean keyboard
, gint keydist
)
340 if (keyboard
) resist
= keydist
- 1; /* resist for one key press */
341 else resist
= config_resist_win
;
342 resist_move_windows(moveresize_client
, resist
, &cur_x
, &cur_y
);
343 if (!keyboard
) resist
= config_resist_edge
;
344 resist_move_monitors(moveresize_client
, resist
, &cur_x
, &cur_y
);
346 client_configure(moveresize_client
, cur_x
, cur_y
, cur_w
, cur_h
,
348 if (config_resize_popup_show
== 2) /* == "Always" */
349 popup_coords(moveresize_client
, "%d x %d",
350 moveresize_client
->frame
->area
.x
,
351 moveresize_client
->frame
->area
.y
);
354 static void do_resize(void)
356 gint x
, y
, w
, h
, lw
, lh
;
358 /* see if it is actually going to resize */
363 client_try_configure(moveresize_client
, &x
, &y
, &w
, &h
,
365 if (!(w
== moveresize_client
->area
.width
&&
366 h
== moveresize_client
->area
.height
))
370 if (config_resize_redraw
&& obt_display_extension_sync
&&
371 moveresize_client
->sync_request
&& moveresize_client
->sync_counter
&&
372 !moveresize_client
->not_responding
)
377 /* are we already waiting for the sync counter to catch up? */
378 if (waiting_for_sync
)
381 /* increment the value we're waiting for */
382 ++moveresize_client
->sync_counter_value
;
383 XSyncIntToValue(&val
, moveresize_client
->sync_counter_value
);
385 /* tell the client what we're waiting for */
386 ce
.xclient
.type
= ClientMessage
;
387 ce
.xclient
.message_type
= OBT_PROP_ATOM(WM_PROTOCOLS
);
388 ce
.xclient
.display
= obt_display
;
389 ce
.xclient
.window
= moveresize_client
->window
;
390 ce
.xclient
.format
= 32;
391 ce
.xclient
.data
.l
[0] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST
);
392 ce
.xclient
.data
.l
[1] = event_time();
393 ce
.xclient
.data
.l
[2] = XSyncValueLow32(val
);
394 ce
.xclient
.data
.l
[3] = XSyncValueHigh32(val
);
395 ce
.xclient
.data
.l
[4] = 0l;
396 XSendEvent(obt_display
, moveresize_client
->window
, FALSE
,
399 waiting_for_sync
= TRUE
;
401 obt_main_loop_timeout_remove(ob_main_loop
, sync_timeout_func
);
402 obt_main_loop_timeout_add(ob_main_loop
, G_USEC_PER_SEC
* 2,
408 client_configure(moveresize_client
, cur_x
, cur_y
, cur_w
, cur_h
,
412 /* this would be better with a fixed width font ... XXX can do it better
413 if there are 2 text boxes */
414 if (config_resize_popup_show
== 2 || /* == "Always" */
415 (config_resize_popup_show
== 1 && /* == "Nonpixel" */
416 moveresize_client
->size_inc
.width
> 1 &&
417 moveresize_client
->size_inc
.height
> 1))
418 popup_coords(moveresize_client
, "%d x %d", lw
, lh
);
422 static gboolean
sync_timeout_func(gpointer data
)
424 waiting_for_sync
= FALSE
; /* we timed out waiting for our sync... */
425 do_resize(); /* ...so let any pending resizes through */
427 return FALSE
; /* don't repeat */
431 static void calc_resize(gboolean keyboard
, gint keydist
, gint
*dw
, gint
*dh
,
434 gint resist
, x
= 0, y
= 0, lw
, lh
, ow
, oh
, nw
, nh
;
443 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
446 case OB_DIRECTION_NORTH
:
447 case OB_DIRECTION_SOUTH
:
448 /* resize the width based on the height */
449 if (moveresize_client
->min_ratio
) {
450 if (nh
* moveresize_client
->min_ratio
> nw
)
451 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
453 if (moveresize_client
->max_ratio
) {
454 if (nh
* moveresize_client
->max_ratio
< nw
)
455 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
459 /* resize the height based on the width */
460 if (moveresize_client
->min_ratio
) {
461 if (nh
* moveresize_client
->min_ratio
> nw
)
462 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
464 if (moveresize_client
->max_ratio
) {
465 if (nh
* moveresize_client
->max_ratio
< nw
)
466 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
471 /* see its actual size (apply aspect ratios) */
472 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
,
478 /* resist_size_* needs the frame size */
479 nw
+= moveresize_client
->frame
->size
.left
+
480 moveresize_client
->frame
->size
.right
;
481 nh
+= moveresize_client
->frame
->size
.top
+
482 moveresize_client
->frame
->size
.bottom
;
484 if (keyboard
) resist
= keydist
- 1; /* resist for one key press */
485 else resist
= config_resist_win
;
486 resist_size_windows(moveresize_client
, resist
, &nw
, &nh
, dir
);
487 if (!keyboard
) resist
= config_resist_edge
;
488 resist_size_monitors(moveresize_client
, resist
, &nw
, &nh
, dir
);
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
;
498 /* take aspect ratios into account for resistance */
500 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
502 if (*dh
!= trydh
) { /* got resisted */
503 /* resize the width based on the height */
504 if (moveresize_client
->min_ratio
) {
505 if (nh
* moveresize_client
->min_ratio
> nw
)
506 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
508 if (moveresize_client
->max_ratio
) {
509 if (nh
* moveresize_client
->max_ratio
< nw
)
510 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
513 if (*dw
!= trydw
) { /* got resisted */
514 /* resize the height based on the width */
515 if (moveresize_client
->min_ratio
) {
516 if (nh
* moveresize_client
->min_ratio
> nw
)
517 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
519 if (moveresize_client
->max_ratio
) {
520 if (nh
* moveresize_client
->max_ratio
< nw
)
521 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
526 /* make sure it's all valid */
527 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
533 static void edge_warp_move_ptr(void)
538 screen_pointer_pos(&x
, &y
);
539 a
= screen_physical_area_all_monitors();
541 switch (edge_warp_dir
) {
542 case OB_DIRECTION_NORTH
:
545 case OB_DIRECTION_EAST
:
548 case OB_DIRECTION_SOUTH
:
551 case OB_DIRECTION_WEST
:
555 g_assert_not_reached();
558 XWarpPointer(obt_display
, 0, obt_root(ob_screen
), 0, 0, 0, 0, x
, y
);
561 static gboolean
edge_warp_delay_func(gpointer data
)
565 /* only fire every second time. so it's fast the first time, but slower
568 d
= screen_find_desktop(screen_desktop
, edge_warp_dir
, TRUE
, FALSE
);
569 if (d
!= screen_desktop
) {
570 if (config_mouse_screenedgewarp
) edge_warp_move_ptr();
571 screen_set_desktop(d
, TRUE
);
574 edge_warp_odd
= !edge_warp_odd
;
576 return TRUE
; /* do repeat ! */
579 static void do_edge_warp(gint x
, gint y
)
584 if (!config_mouse_screenedgetime
) return;
588 for (i
= 0; i
< screen_num_monitors
; ++i
) {
589 const Rect
*a
= screen_physical_area_monitor(i
);
590 if (x
== RECT_LEFT(*a
)) dir
= OB_DIRECTION_WEST
;
591 if (x
== RECT_RIGHT(*a
)) dir
= OB_DIRECTION_EAST
;
592 if (y
== RECT_TOP(*a
)) dir
= OB_DIRECTION_NORTH
;
593 if (y
== RECT_BOTTOM(*a
)) dir
= OB_DIRECTION_SOUTH
;
595 /* try check for xinerama boundaries */
596 if ((x
+ 1 == RECT_LEFT(*a
) || x
- 1 == RECT_RIGHT(*a
)) &&
597 (dir
== OB_DIRECTION_WEST
|| dir
== OB_DIRECTION_EAST
))
601 if ((y
+ 1 == RECT_TOP(*a
) || y
- 1 == RECT_BOTTOM(*a
)) &&
602 (dir
== OB_DIRECTION_NORTH
|| dir
== OB_DIRECTION_SOUTH
))
608 if (dir
!= edge_warp_dir
) {
610 if (dir
!= (ObDirection
)-1) {
611 edge_warp_odd
= TRUE
; /* switch on the first timeout */
612 obt_main_loop_timeout_add(ob_main_loop
,
613 config_mouse_screenedgetime
* 1000,
614 edge_warp_delay_func
,
621 static void cancel_edge_warp(void)
623 obt_main_loop_timeout_remove(ob_main_loop
, edge_warp_delay_func
);
626 static void move_with_keys(KeySym sym
, guint state
)
628 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
629 gint opx
, px
, opy
, py
;
632 /* shift means jump to edge */
633 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
))
639 dir
= OB_DIRECTION_EAST
;
640 else if (sym
== XK_Left
)
641 dir
= OB_DIRECTION_WEST
;
642 else if (sym
== XK_Down
)
643 dir
= OB_DIRECTION_SOUTH
;
644 else /* sym == XK_Up */
645 dir
= OB_DIRECTION_NORTH
;
647 client_find_move_directional(moveresize_client
, dir
, &x
, &y
);
648 dx
= x
- moveresize_client
->area
.x
;
649 dy
= y
- moveresize_client
->area
.y
;
651 /* control means fine grained */
653 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
662 else if (sym
== XK_Left
)
664 else if (sym
== XK_Down
)
666 else /* if (sym == XK_Up) */
670 screen_pointer_pos(&opx
, &opy
);
671 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
672 /* steal the motion events this causes */
673 XSync(obt_display
, FALSE
);
676 while (xqueue_remove_local(&ce
, xqueue_match_type
,
677 GINT_TO_POINTER(MotionNotify
)));
679 screen_pointer_pos(&px
, &py
);
685 /* because the cursor moves even though the window does
686 not nessesarily (resistance), this adjusts where the curor
687 thinks it started so that it keeps up with where the window
689 start_x
+= (px
- opx
) - (cur_x
- ox
);
690 start_y
+= (py
- opy
) - (cur_y
- oy
);
693 static void resize_with_keys(KeySym sym
, guint state
)
695 gint dw
= 0, dh
= 0, pdx
= 0, pdy
= 0, opx
, opy
, px
, py
;
699 /* pick the edge if it needs to move */
700 if (sym
== XK_Right
) {
701 dir
= OB_DIRECTION_EAST
;
702 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
703 key_resize_edge
!= OB_DIRECTION_EAST
)
705 key_resize_edge
= OB_DIRECTION_EAST
;
708 } else if (sym
== XK_Left
) {
709 dir
= OB_DIRECTION_WEST
;
710 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
711 key_resize_edge
!= OB_DIRECTION_EAST
)
713 key_resize_edge
= OB_DIRECTION_WEST
;
716 } else if (sym
== XK_Up
) {
717 dir
= OB_DIRECTION_NORTH
;
718 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
719 key_resize_edge
!= OB_DIRECTION_SOUTH
)
721 key_resize_edge
= OB_DIRECTION_NORTH
;
724 } else /* if (sym == XK_Down) */ {
725 dir
= OB_DIRECTION_SOUTH
;
726 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
727 key_resize_edge
!= OB_DIRECTION_SOUTH
)
729 key_resize_edge
= OB_DIRECTION_SOUTH
;
734 /* shift means jump to edge */
735 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
))
740 dir
= OB_DIRECTION_EAST
;
741 else if (sym
== XK_Left
)
742 dir
= OB_DIRECTION_WEST
;
743 else if (sym
== XK_Down
)
744 dir
= OB_DIRECTION_SOUTH
;
745 else /* if (sym == XK_Up)) */
746 dir
= OB_DIRECTION_NORTH
;
748 client_find_resize_directional(moveresize_client
, key_resize_edge
,
749 key_resize_edge
== dir
,
751 dw
= w
- moveresize_client
->area
.width
;
752 dh
= h
- moveresize_client
->area
.height
;
756 /* control means fine grained */
757 if (moveresize_client
->size_inc
.width
> 1) {
758 distw
= moveresize_client
->size_inc
.width
;
762 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
771 if (moveresize_client
->size_inc
.height
> 1) {
772 disth
= moveresize_client
->size_inc
.height
;
776 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
786 if (key_resize_edge
== OB_DIRECTION_WEST
) {
787 if (dir
== OB_DIRECTION_WEST
)
792 else if (key_resize_edge
== OB_DIRECTION_EAST
) {
793 if (dir
== OB_DIRECTION_EAST
)
798 else if (key_resize_edge
== OB_DIRECTION_NORTH
) {
799 if (dir
== OB_DIRECTION_NORTH
)
804 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
805 if (dir
== OB_DIRECTION_SOUTH
)
812 calc_resize(TRUE
, resist
, &dw
, &dh
, dir
);
813 if (key_resize_edge
== OB_DIRECTION_WEST
)
815 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
820 /* how to move the pointer to keep up with the change */
821 if (key_resize_edge
== OB_DIRECTION_WEST
)
823 else if (key_resize_edge
== OB_DIRECTION_EAST
)
825 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
827 else if (key_resize_edge
== OB_DIRECTION_SOUTH
)
830 screen_pointer_pos(&opx
, &opy
);
831 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, pdx
, pdy
);
832 /* steal the motion events this causes */
833 XSync(obt_display
, FALSE
);
836 while (xqueue_remove_local(&ce
, xqueue_match_type
,
837 GINT_TO_POINTER(MotionNotify
)));
839 screen_pointer_pos(&px
, &py
);
843 /* because the cursor moves even though the window does
844 not nessesarily (resistance), this adjusts where the cursor
845 thinks it started so that it keeps up with where the window
847 start_x
+= (px
- opx
) - dw
;
848 start_y
+= (py
- opy
) - dh
;
852 gboolean
moveresize_event(XEvent
*e
)
854 gboolean used
= FALSE
;
856 if (!moveresize_in_progress
) return FALSE
;
858 if (e
->type
== ButtonPress
) {
860 start_x
= e
->xbutton
.x_root
;
861 start_y
= e
->xbutton
.y_root
;
862 button
= e
->xbutton
.button
; /* this will end it now */
864 used
= e
->xbutton
.button
== button
;
865 } else if (e
->type
== ButtonRelease
) {
866 if (!button
|| e
->xbutton
.button
== button
) {
867 moveresize_end(FALSE
);
870 } else if (e
->type
== MotionNotify
) {
872 cur_x
= start_cx
+ e
->xmotion
.x_root
- start_x
;
873 cur_y
= start_cy
+ e
->xmotion
.y_root
- start_y
;
875 do_edge_warp(e
->xmotion
.x_root
, e
->xmotion
.y_root
);
880 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
)) {
881 dw
= -(e
->xmotion
.x_root
- start_x
);
882 dh
= -(e
->xmotion
.y_root
- start_y
);
883 dir
= OB_DIRECTION_NORTHWEST
;
884 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
)) {
886 dh
= -(e
->xmotion
.y_root
- start_y
);
887 dir
= OB_DIRECTION_NORTH
;
889 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
)) {
890 dw
= (e
->xmotion
.x_root
- start_x
);
891 dh
= -(e
->xmotion
.y_root
- start_y
);
892 dir
= OB_DIRECTION_NORTHEAST
;
893 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT
)) {
894 dw
= (e
->xmotion
.x_root
- start_x
);
896 dir
= OB_DIRECTION_EAST
;
898 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
)) {
899 dw
= (e
->xmotion
.x_root
- start_x
);
900 dh
= (e
->xmotion
.y_root
- start_y
);
901 dir
= OB_DIRECTION_SOUTHEAST
;
902 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM
))
905 dh
= (e
->xmotion
.y_root
- start_y
);
906 dir
= OB_DIRECTION_SOUTH
;
908 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
)) {
909 dw
= -(e
->xmotion
.x_root
- start_x
);
910 dh
= (e
->xmotion
.y_root
- start_y
);
911 dir
= OB_DIRECTION_SOUTHWEST
;
912 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
)) {
913 dw
= -(e
->xmotion
.x_root
- start_x
);
915 dir
= OB_DIRECTION_WEST
;
917 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
918 dw
= (e
->xmotion
.x_root
- start_x
);
919 dh
= (e
->xmotion
.y_root
- start_y
);
920 dir
= OB_DIRECTION_SOUTHEAST
;
922 g_assert_not_reached();
924 dw
-= cur_w
- start_cw
;
925 dh
-= cur_h
- start_ch
;
927 calc_resize(FALSE
, 0, &dw
, &dh
, dir
);
931 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
932 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
) ||
933 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
))
937 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
938 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
) ||
939 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
))
947 } else if (e
->type
== KeyPress
) {
948 KeySym sym
= obt_keyboard_keypress_to_keysym(e
);
950 if (sym
== XK_Escape
) {
951 moveresize_end(TRUE
);
953 } else if (sym
== XK_Return
|| sym
== XK_KP_Enter
) {
954 moveresize_end(FALSE
);
956 } else if (sym
== XK_Right
|| sym
== XK_Left
||
957 sym
== XK_Up
|| sym
== XK_Down
)
959 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
960 resize_with_keys(sym
, e
->xkey
.state
);
963 OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
))
965 move_with_keys(sym
, e
->xkey
.state
);
971 else if (e
->type
== obt_display_extension_sync_basep
+ XSyncAlarmNotify
)
973 waiting_for_sync
= FALSE
; /* we got our sync... */
974 do_resize(); /* ...so try resize if there is more change pending */