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"
29 #include "moveresize.h"
33 #include "obrender/render.h"
34 #include "obrender/theme.h"
35 #include "obt/display.h"
36 #include "obt/xqueue.h"
38 #include "obt/keyboard.h"
43 /* how far windows move and resize with the keyboard arrows */
45 #define SYNC_TIMEOUTS 4
47 gboolean moveresize_in_progress
= FALSE
;
48 ObClient
*moveresize_client
= NULL
;
50 XSyncAlarm moveresize_alarm
= None
;
53 static gboolean moving
= FALSE
; /* TRUE - moving, FALSE - resizing */
55 /* starting geometry for the window being moved/resized, so it can be
57 static gint start_x
, start_y
, start_cx
, start_cy
, start_cw
, start_ch
;
58 static gboolean was_max_horz
, was_max_vert
;
59 static Rect pre_max_area
;
60 static gint cur_x
, cur_y
, cur_w
, cur_h
;
62 static guint32 corner
;
63 static ObDirection edge_warp_dir
= -1;
64 static gboolean edge_warp_odd
= FALSE
;
65 static guint edge_warp_timer
= 0;
66 static ObDirection key_resize_edge
= -1;
67 static guint waiting_for_sync
;
69 static guint sync_timer
= 0;
72 static ObPopup
*popup
= NULL
;
74 static void do_move(gboolean keyboard
, gint keydist
);
75 static void do_resize(void);
76 static void do_edge_warp(gint x
, gint y
);
77 static void cancel_edge_warp();
79 static gboolean
sync_timeout_func(gpointer data
);
82 static void client_dest(ObClient
*client
, gpointer data
)
84 if (moveresize_client
== client
)
88 void moveresize_startup(gboolean reconfig
)
91 popup_set_text_align(popup
, RR_JUSTIFY_CENTER
);
94 client_add_destroy_notify(client_dest
, NULL
);
97 void moveresize_shutdown(gboolean reconfig
)
100 if (moveresize_in_progress
)
101 moveresize_end(FALSE
);
102 client_remove_destroy_notify(client_dest
);
109 static void popup_coords(ObClient
*c
, const gchar
*format
, gint a
, gint b
)
113 text
= g_strdup_printf(format
, a
, b
);
114 if (config_resize_popup_pos
== OB_RESIZE_POS_TOP
)
115 popup_position(popup
, SouthGravity
,
117 + c
->frame
->area
.width
/2,
118 c
->frame
->area
.y
- ob_rr_theme
->fbwidth
);
119 else if (config_resize_popup_pos
== OB_RESIZE_POS_CENTER
)
120 popup_position(popup
, CenterGravity
,
121 c
->frame
->area
.x
+ c
->frame
->area
.width
/ 2,
122 c
->frame
->area
.y
+ c
->frame
->area
.height
/ 2);
124 const Rect
*area
= screen_physical_area_active();
127 x
= config_resize_popup_fixed
.x
.pos
;
128 if (config_resize_popup_fixed
.x
.center
)
129 x
= area
->x
+ area
->width
/2;
130 else if (config_resize_popup_fixed
.x
.opposite
)
131 x
= RECT_RIGHT(*area
) - x
;
135 y
= config_resize_popup_fixed
.y
.pos
;
136 if (config_resize_popup_fixed
.y
.center
)
137 y
= area
->y
+ area
->height
/2;
138 else if (config_resize_popup_fixed
.y
.opposite
)
139 y
= RECT_RIGHT(*area
) - y
;
143 if (config_resize_popup_fixed
.x
.center
) {
144 if (config_resize_popup_fixed
.y
.center
)
145 gravity
= CenterGravity
;
146 else if (config_resize_popup_fixed
.y
.opposite
)
147 gravity
= SouthGravity
;
149 gravity
= NorthGravity
;
151 else if (config_resize_popup_fixed
.x
.opposite
) {
152 if (config_resize_popup_fixed
.y
.center
)
153 gravity
= EastGravity
;
154 else if (config_resize_popup_fixed
.y
.opposite
)
155 gravity
= SouthEastGravity
;
157 gravity
= NorthEastGravity
;
160 if (config_resize_popup_fixed
.y
.center
)
161 gravity
= WestGravity
;
162 else if (config_resize_popup_fixed
.y
.opposite
)
163 gravity
= SouthWestGravity
;
165 gravity
= NorthWestGravity
;
168 popup_position(popup
, gravity
, x
, y
);
170 popup_show(popup
, text
);
174 void moveresize_start(ObClient
*c
, gint x
, gint y
, guint b
, guint32 cnr
)
177 gboolean mv
= (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE
) ||
178 cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
));
182 if (moveresize_in_progress
|| !c
->frame
->visible
||
184 (c
->functions
& OB_CLIENT_FUNC_MOVE
) :
185 (c
->functions
& OB_CLIENT_FUNC_RESIZE
)))
188 if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
)) {
189 cur
= OB_CURSOR_NORTHWEST
;
192 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
)) {
193 cur
= OB_CURSOR_NORTH
;
196 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
)) {
197 cur
= OB_CURSOR_NORTHEAST
;
200 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT
))
201 cur
= OB_CURSOR_EAST
;
202 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
))
203 cur
= OB_CURSOR_SOUTHEAST
;
204 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM
))
205 cur
= OB_CURSOR_SOUTH
;
206 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
)) {
207 cur
= OB_CURSOR_SOUTHWEST
;
210 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
)) {
211 cur
= OB_CURSOR_WEST
;
214 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
))
215 cur
= OB_CURSOR_SOUTHEAST
;
216 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE
))
217 cur
= OB_CURSOR_MOVE
;
218 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
))
219 cur
= OB_CURSOR_MOVE
;
221 g_assert_not_reached();
223 /* keep the pointer bounded to the screen for move/resize */
224 if (!grab_pointer(FALSE
, TRUE
, cur
))
226 if (!grab_keyboard()) {
231 frame_end_iconify_animation(c
->frame
);
234 moveresize_client
= c
;
235 start_cx
= c
->area
.x
;
236 start_cy
= c
->area
.y
;
237 start_cw
= c
->area
.width
;
238 start_ch
= c
->area
.height
;
239 /* these adjustments for the size_inc make resizing a terminal more
240 friendly. you essentially start the resize in the middle of the
241 increment instead of at 0, so you have to move half an increment
242 either way instead of a full increment one and 1 px the other. */
243 start_x
= x
- (mv
? 0 : left
* c
->size_inc
.width
/ 2);
244 start_y
= y
- (mv
? 0 : up
* c
->size_inc
.height
/ 2);
247 key_resize_edge
= -1;
249 /* default to not putting max back on cancel */
250 was_max_horz
= was_max_vert
= FALSE
;
253 have to change start_cx and start_cy if going to do this..
254 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
255 corner == prop_atoms.net_wm_moveresize_size_keyboard)
256 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
257 c->area.width / 2, c->area.height / 2);
265 moveresize_in_progress
= TRUE
;
266 waiting_for_sync
= 0;
269 if (config_resize_redraw
&& !moving
&& obt_display_extension_sync
&&
270 moveresize_client
->sync_request
&& moveresize_client
->sync_counter
&&
271 !moveresize_client
->not_responding
)
273 /* Initialize values for the resize syncing, and create an alarm for
274 the client's xsync counter */
277 XSyncAlarmAttributes aa
;
279 /* set the counter to an initial value */
280 XSyncIntToValue(&val
, 0);
281 XSyncSetCounter(obt_display
, moveresize_client
->sync_counter
, val
);
283 /* this will be incremented when we tell the client what we're
285 moveresize_client
->sync_counter_value
= 0;
287 /* the next sequence we're waiting for with the alarm */
288 XSyncIntToValue(&val
, 1);
290 /* set an alarm on the counter */
291 aa
.trigger
.counter
= moveresize_client
->sync_counter
;
292 aa
.trigger
.wait_value
= val
;
293 aa
.trigger
.value_type
= XSyncAbsolute
;
294 aa
.trigger
.test_type
= XSyncPositiveTransition
;
296 XSyncIntToValue(&aa
.delta
, 1);
297 moveresize_alarm
= XSyncCreateAlarm(obt_display
,
309 void moveresize_end(gboolean cancel
)
318 /* turn off the alarm */
319 if (moveresize_alarm
!= None
) {
320 XSyncDestroyAlarm(obt_display
, moveresize_alarm
);
321 moveresize_alarm
= None
;
324 if (sync_timer
) g_source_remove(sync_timer
);
329 /* don't use client_move() here, use the same width/height as
330 we've been using during the move, otherwise we get different results
331 when moving maximized windows between monitors of different sizes !
333 client_configure(moveresize_client
,
334 (cancel
? start_cx
: cur_x
),
335 (cancel
? start_cy
: cur_y
),
336 (cancel
? start_cw
: cur_w
),
337 (cancel
? start_ch
: cur_h
),
340 /* restore the client's maximized state. do this after putting the window
341 back in its original spot to minimize visible flicker */
342 if (cancel
&& (was_max_horz
|| was_max_vert
)) {
343 const gboolean h
= moveresize_client
->max_horz
;
344 const gboolean v
= moveresize_client
->max_vert
;
346 client_maximize(moveresize_client
, TRUE
,
347 was_max_horz
&& was_max_vert
? 0 :
348 (was_max_horz
? 1 : 2));
350 /* replace the premax values with the ones we had saved if
351 the client doesn't have any already set */
352 if (was_max_horz
&& !h
) {
353 moveresize_client
->pre_max_area
.x
= pre_max_area
.x
;
354 moveresize_client
->pre_max_area
.width
= pre_max_area
.width
;
356 if (was_max_vert
&& !v
) {
357 moveresize_client
->pre_max_area
.y
= pre_max_area
.y
;
358 moveresize_client
->pre_max_area
.height
= pre_max_area
.height
;
362 /* dont edge warp after its ended */
365 moveresize_in_progress
= FALSE
;
366 moveresize_client
= NULL
;
369 static void do_move(gboolean keyboard
, gint keydist
)
373 if (keyboard
) resist
= keydist
- 1; /* resist for one key press */
374 else resist
= config_resist_win
;
375 resist_move_windows(moveresize_client
, resist
, &cur_x
, &cur_y
);
376 if (!keyboard
) resist
= config_resist_edge
;
377 resist_move_monitors(moveresize_client
, resist
, &cur_x
, &cur_y
);
379 client_configure(moveresize_client
, cur_x
, cur_y
, cur_w
, cur_h
,
381 if (config_resize_popup_show
== 2) /* == "Always" */
382 popup_coords(moveresize_client
, "%d x %d",
383 moveresize_client
->frame
->area
.x
,
384 moveresize_client
->frame
->area
.y
);
387 static void do_resize(void)
389 gint x
, y
, w
, h
, lw
, lh
;
391 /* see if it is actually going to resize
392 USE cur_x AND cur_y HERE ! Otherwise the try_configure won't know
393 what struts to use !!
399 client_try_configure(moveresize_client
, &x
, &y
, &w
, &h
,
401 if (!(w
== moveresize_client
->area
.width
&&
402 h
== moveresize_client
->area
.height
) &&
403 /* if waiting_for_sync == 0, then we aren't waiting.
404 if it is > SYNC_TIMEOUTS, then we have timed out
405 that many times already, so forget about waiting more */
406 (waiting_for_sync
== 0 || waiting_for_sync
> SYNC_TIMEOUTS
))
409 if (config_resize_redraw
&& obt_display_extension_sync
&&
410 /* don't send another sync when one is pending */
411 waiting_for_sync
== 0 &&
412 moveresize_client
->sync_request
&&
413 moveresize_client
->sync_counter
&&
414 !moveresize_client
->not_responding
)
419 /* increment the value we're waiting for */
420 ++moveresize_client
->sync_counter_value
;
421 XSyncIntToValue(&val
, moveresize_client
->sync_counter_value
);
423 /* tell the client what we're waiting for */
424 ce
.xclient
.type
= ClientMessage
;
425 ce
.xclient
.message_type
= OBT_PROP_ATOM(WM_PROTOCOLS
);
426 ce
.xclient
.display
= obt_display
;
427 ce
.xclient
.window
= moveresize_client
->window
;
428 ce
.xclient
.format
= 32;
429 ce
.xclient
.data
.l
[0] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST
);
430 ce
.xclient
.data
.l
[1] = event_time();
431 ce
.xclient
.data
.l
[2] = XSyncValueLow32(val
);
432 ce
.xclient
.data
.l
[3] = XSyncValueHigh32(val
);
433 ce
.xclient
.data
.l
[4] = 0l;
434 XSendEvent(obt_display
, moveresize_client
->window
, FALSE
,
437 waiting_for_sync
= 1;
439 if (sync_timer
) g_source_remove(sync_timer
);
440 sync_timer
= g_timeout_add(2000, sync_timeout_func
, NULL
);
444 /* force a ConfigureNotify, it is part of the spec for SYNC resizing
445 and MUST follow the sync counter notification */
446 client_configure(moveresize_client
, cur_x
, cur_y
, cur_w
, cur_h
,
450 /* this would be better with a fixed width font ... XXX can do it better
451 if there are 2 text boxes */
452 if (config_resize_popup_show
== 2 || /* == "Always" */
453 (config_resize_popup_show
== 1 && /* == "Nonpixel" */
454 moveresize_client
->size_inc
.width
> 1 &&
455 moveresize_client
->size_inc
.height
> 1))
456 popup_coords(moveresize_client
, "%d x %d", lw
, lh
);
460 static gboolean
sync_timeout_func(gpointer data
)
462 ++waiting_for_sync
; /* we timed out waiting for our sync... */
463 do_resize(); /* ...so let any pending resizes through */
465 if (waiting_for_sync
> SYNC_TIMEOUTS
) {
467 return FALSE
; /* don't repeat */
470 return TRUE
; /* keep waiting */
474 static void calc_resize(gboolean keyboard
, gint keydist
, gint
*dw
, gint
*dh
,
477 gint resist
, x
= 0, y
= 0, lw
, lh
, ow
, oh
, nw
, nh
;
486 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
489 case OB_DIRECTION_NORTH
:
490 case OB_DIRECTION_SOUTH
:
491 /* resize the width based on the height */
492 if (moveresize_client
->min_ratio
) {
493 if (nh
* moveresize_client
->min_ratio
> nw
)
494 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
496 if (moveresize_client
->max_ratio
) {
497 if (nh
* moveresize_client
->max_ratio
< nw
)
498 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
502 /* resize the height based on the width */
503 if (moveresize_client
->min_ratio
) {
504 if (nh
* moveresize_client
->min_ratio
> nw
)
505 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
507 if (moveresize_client
->max_ratio
) {
508 if (nh
* moveresize_client
->max_ratio
< nw
)
509 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
514 /* see its actual size (apply aspect ratios) */
515 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
,
521 /* resist_size_* needs the frame size */
522 nw
+= moveresize_client
->frame
->size
.left
+
523 moveresize_client
->frame
->size
.right
;
524 nh
+= moveresize_client
->frame
->size
.top
+
525 moveresize_client
->frame
->size
.bottom
;
527 if (keyboard
) resist
= keydist
- 1; /* resist for one key press */
528 else resist
= config_resist_win
;
529 resist_size_windows(moveresize_client
, resist
, &nw
, &nh
, dir
);
530 if (!keyboard
) resist
= config_resist_edge
;
531 resist_size_monitors(moveresize_client
, resist
, &nw
, &nh
, dir
);
533 nw
-= moveresize_client
->frame
->size
.left
+
534 moveresize_client
->frame
->size
.right
;
535 nh
-= moveresize_client
->frame
->size
.top
+
536 moveresize_client
->frame
->size
.bottom
;
541 /* take aspect ratios into account for resistance */
543 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
545 if (*dh
!= trydh
) { /* got resisted */
546 /* resize the width based on the height */
547 if (moveresize_client
->min_ratio
) {
548 if (nh
* moveresize_client
->min_ratio
> nw
)
549 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
551 if (moveresize_client
->max_ratio
) {
552 if (nh
* moveresize_client
->max_ratio
< nw
)
553 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
556 if (*dw
!= trydw
) { /* got resisted */
557 /* resize the height based on the width */
558 if (moveresize_client
->min_ratio
) {
559 if (nh
* moveresize_client
->min_ratio
> nw
)
560 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
562 if (moveresize_client
->max_ratio
) {
563 if (nh
* moveresize_client
->max_ratio
< nw
)
564 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
569 /* make sure it's all valid */
570 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
576 static void edge_warp_move_ptr(void)
581 screen_pointer_pos(&x
, &y
);
582 a
= screen_physical_area_all_monitors();
584 switch (edge_warp_dir
) {
585 case OB_DIRECTION_NORTH
:
588 case OB_DIRECTION_EAST
:
591 case OB_DIRECTION_SOUTH
:
594 case OB_DIRECTION_WEST
:
598 g_assert_not_reached();
601 XWarpPointer(obt_display
, 0, obt_root(ob_screen
), 0, 0, 0, 0, x
, y
);
604 static gboolean
edge_warp_delay_func(gpointer data
)
608 /* only fire every second time. so it's fast the first time, but slower
611 d
= screen_find_desktop(screen_desktop
, edge_warp_dir
, TRUE
, FALSE
);
612 if (d
!= screen_desktop
) {
613 if (config_mouse_screenedgewarp
) edge_warp_move_ptr();
614 screen_set_desktop(d
, TRUE
);
617 edge_warp_odd
= !edge_warp_odd
;
619 return TRUE
; /* do repeat ! */
622 static void do_edge_warp(gint x
, gint y
)
627 if (!config_mouse_screenedgetime
) return;
631 for (i
= 0; i
< screen_num_monitors
; ++i
) {
632 const Rect
*a
= screen_physical_area_monitor(i
);
633 if (x
== RECT_LEFT(*a
)) dir
= OB_DIRECTION_WEST
;
634 if (x
== RECT_RIGHT(*a
)) dir
= OB_DIRECTION_EAST
;
635 if (y
== RECT_TOP(*a
)) dir
= OB_DIRECTION_NORTH
;
636 if (y
== RECT_BOTTOM(*a
)) dir
= OB_DIRECTION_SOUTH
;
638 /* try check for xinerama boundaries */
639 if ((x
+ 1 == RECT_LEFT(*a
) || x
- 1 == RECT_RIGHT(*a
)) &&
640 (dir
== OB_DIRECTION_WEST
|| dir
== OB_DIRECTION_EAST
))
644 if ((y
+ 1 == RECT_TOP(*a
) || y
- 1 == RECT_BOTTOM(*a
)) &&
645 (dir
== OB_DIRECTION_NORTH
|| dir
== OB_DIRECTION_SOUTH
))
651 if (dir
!= edge_warp_dir
) {
653 if (dir
!= (ObDirection
)-1) {
654 edge_warp_odd
= TRUE
; /* switch on the first timeout */
655 edge_warp_timer
= g_timeout_add(config_mouse_screenedgetime
,
656 edge_warp_delay_func
, NULL
);
662 static void cancel_edge_warp(void)
664 if (edge_warp_timer
) g_source_remove(edge_warp_timer
);
668 static void move_with_keys(KeySym sym
, guint state
)
670 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
671 gint opx
, px
, opy
, py
;
674 /* shift means jump to edge */
675 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
))
681 dir
= OB_DIRECTION_EAST
;
682 else if (sym
== XK_Left
)
683 dir
= OB_DIRECTION_WEST
;
684 else if (sym
== XK_Down
)
685 dir
= OB_DIRECTION_SOUTH
;
686 else /* sym == XK_Up */
687 dir
= OB_DIRECTION_NORTH
;
689 client_find_move_directional(moveresize_client
, dir
, &x
, &y
);
690 dx
= x
- moveresize_client
->area
.x
;
691 dy
= y
- moveresize_client
->area
.y
;
693 /* control means fine grained */
695 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
704 else if (sym
== XK_Left
)
706 else if (sym
== XK_Down
)
708 else /* if (sym == XK_Up) */
712 screen_pointer_pos(&opx
, &opy
);
713 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
714 /* steal the motion events this causes */
715 XSync(obt_display
, FALSE
);
718 while (xqueue_remove_local(&ce
, xqueue_match_type
,
719 GINT_TO_POINTER(MotionNotify
)));
721 screen_pointer_pos(&px
, &py
);
727 /* because the cursor moves even though the window does
728 not nessesarily (resistance), this adjusts where the curor
729 thinks it started so that it keeps up with where the window
731 start_x
+= (px
- opx
) - (cur_x
- ox
);
732 start_y
+= (py
- opy
) - (cur_y
- oy
);
735 static void resize_with_keys(KeySym sym
, guint state
)
737 gint dw
= 0, dh
= 0, pdx
= 0, pdy
= 0, opx
, opy
, px
, py
;
741 /* pick the edge if it needs to move */
742 if (sym
== XK_Right
) {
743 dir
= OB_DIRECTION_EAST
;
744 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
745 key_resize_edge
!= OB_DIRECTION_EAST
)
747 key_resize_edge
= OB_DIRECTION_EAST
;
750 } else if (sym
== XK_Left
) {
751 dir
= OB_DIRECTION_WEST
;
752 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
753 key_resize_edge
!= OB_DIRECTION_EAST
)
755 key_resize_edge
= OB_DIRECTION_WEST
;
758 } else if (sym
== XK_Up
) {
759 dir
= OB_DIRECTION_NORTH
;
760 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
761 key_resize_edge
!= OB_DIRECTION_SOUTH
)
763 key_resize_edge
= OB_DIRECTION_NORTH
;
766 } else /* if (sym == XK_Down) */ {
767 dir
= OB_DIRECTION_SOUTH
;
768 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
769 key_resize_edge
!= OB_DIRECTION_SOUTH
)
771 key_resize_edge
= OB_DIRECTION_SOUTH
;
776 /* shift means jump to edge */
777 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
))
782 dir
= OB_DIRECTION_EAST
;
783 else if (sym
== XK_Left
)
784 dir
= OB_DIRECTION_WEST
;
785 else if (sym
== XK_Down
)
786 dir
= OB_DIRECTION_SOUTH
;
787 else /* if (sym == XK_Up)) */
788 dir
= OB_DIRECTION_NORTH
;
790 client_find_resize_directional(moveresize_client
, key_resize_edge
,
791 key_resize_edge
== dir
,
793 dw
= w
- moveresize_client
->area
.width
;
794 dh
= h
- moveresize_client
->area
.height
;
798 /* control means fine grained */
799 if (moveresize_client
->size_inc
.width
> 1) {
800 distw
= moveresize_client
->size_inc
.width
;
804 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
813 if (moveresize_client
->size_inc
.height
> 1) {
814 disth
= moveresize_client
->size_inc
.height
;
818 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
828 if (key_resize_edge
== OB_DIRECTION_WEST
) {
829 if (dir
== OB_DIRECTION_WEST
)
834 else if (key_resize_edge
== OB_DIRECTION_EAST
) {
835 if (dir
== OB_DIRECTION_EAST
)
840 else if (key_resize_edge
== OB_DIRECTION_NORTH
) {
841 if (dir
== OB_DIRECTION_NORTH
)
846 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
847 if (dir
== OB_DIRECTION_SOUTH
)
854 if (moveresize_client
->max_horz
&&
855 (key_resize_edge
== OB_DIRECTION_WEST
||
856 key_resize_edge
== OB_DIRECTION_EAST
))
860 pre_max_area
.x
= moveresize_client
->pre_max_area
.x
;
861 pre_max_area
.width
= moveresize_client
->pre_max_area
.width
;
863 moveresize_client
->pre_max_area
.x
= cur_x
;
864 moveresize_client
->pre_max_area
.width
= cur_w
;
865 client_maximize(moveresize_client
, FALSE
, 1);
867 else if (moveresize_client
->max_vert
&&
868 (key_resize_edge
== OB_DIRECTION_NORTH
||
869 key_resize_edge
== OB_DIRECTION_SOUTH
))
873 pre_max_area
.y
= moveresize_client
->pre_max_area
.y
;
874 pre_max_area
.height
= moveresize_client
->pre_max_area
.height
;
876 moveresize_client
->pre_max_area
.y
= cur_y
;
877 moveresize_client
->pre_max_area
.height
= cur_h
;
878 client_maximize(moveresize_client
, FALSE
, 2);
881 calc_resize(TRUE
, resist
, &dw
, &dh
, dir
);
882 if (key_resize_edge
== OB_DIRECTION_WEST
)
884 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
889 /* how to move the pointer to keep up with the change */
890 if (key_resize_edge
== OB_DIRECTION_WEST
)
892 else if (key_resize_edge
== OB_DIRECTION_EAST
)
894 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
896 else if (key_resize_edge
== OB_DIRECTION_SOUTH
)
899 screen_pointer_pos(&opx
, &opy
);
900 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, pdx
, pdy
);
901 /* steal the motion events this causes */
902 XSync(obt_display
, FALSE
);
905 while (xqueue_remove_local(&ce
, xqueue_match_type
,
906 GINT_TO_POINTER(MotionNotify
)));
908 screen_pointer_pos(&px
, &py
);
912 /* because the cursor moves even though the window does
913 not nessesarily (resistance), this adjusts where the cursor
914 thinks it started so that it keeps up with where the window
916 start_x
+= (px
- opx
) - dw
;
917 start_y
+= (py
- opy
) - dh
;
921 gboolean
moveresize_event(XEvent
*e
)
923 gboolean used
= FALSE
;
925 if (!moveresize_in_progress
) return FALSE
;
927 if (e
->type
== ButtonPress
) {
929 start_x
= e
->xbutton
.x_root
;
930 start_y
= e
->xbutton
.y_root
;
931 button
= e
->xbutton
.button
; /* this will end it now */
933 used
= e
->xbutton
.button
== button
;
934 } else if (e
->type
== ButtonRelease
) {
935 if (!button
|| e
->xbutton
.button
== button
) {
936 moveresize_end(FALSE
);
939 } else if (e
->type
== MotionNotify
) {
941 cur_x
= start_cx
+ e
->xmotion
.x_root
- start_x
;
942 cur_y
= start_cy
+ e
->xmotion
.y_root
- start_y
;
944 do_edge_warp(e
->xmotion
.x_root
, e
->xmotion
.y_root
);
949 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
)) {
950 dw
= -(e
->xmotion
.x_root
- start_x
);
951 dh
= -(e
->xmotion
.y_root
- start_y
);
952 dir
= OB_DIRECTION_NORTHWEST
;
953 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
)) {
955 dh
= -(e
->xmotion
.y_root
- start_y
);
956 dir
= OB_DIRECTION_NORTH
;
958 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
)) {
959 dw
= (e
->xmotion
.x_root
- start_x
);
960 dh
= -(e
->xmotion
.y_root
- start_y
);
961 dir
= OB_DIRECTION_NORTHEAST
;
962 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT
)) {
963 dw
= (e
->xmotion
.x_root
- start_x
);
965 dir
= OB_DIRECTION_EAST
;
967 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
)) {
968 dw
= (e
->xmotion
.x_root
- start_x
);
969 dh
= (e
->xmotion
.y_root
- start_y
);
970 dir
= OB_DIRECTION_SOUTHEAST
;
971 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM
))
974 dh
= (e
->xmotion
.y_root
- start_y
);
975 dir
= OB_DIRECTION_SOUTH
;
977 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
)) {
978 dw
= -(e
->xmotion
.x_root
- start_x
);
979 dh
= (e
->xmotion
.y_root
- start_y
);
980 dir
= OB_DIRECTION_SOUTHWEST
;
981 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
)) {
982 dw
= -(e
->xmotion
.x_root
- start_x
);
984 dir
= OB_DIRECTION_WEST
;
986 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
987 dw
= (e
->xmotion
.x_root
- start_x
);
988 dh
= (e
->xmotion
.y_root
- start_y
);
989 dir
= OB_DIRECTION_SOUTHEAST
;
991 g_assert_not_reached();
993 /* override the client's max state if desired */
994 if (ABS(dw
) >= config_resist_edge
) {
995 if (moveresize_client
->max_horz
) {
998 pre_max_area
.x
= moveresize_client
->pre_max_area
.x
;
999 pre_max_area
.width
= moveresize_client
->pre_max_area
.width
;
1001 moveresize_client
->pre_max_area
.x
= cur_x
;
1002 moveresize_client
->pre_max_area
.width
= cur_w
;
1003 client_maximize(moveresize_client
, FALSE
, 1);
1006 else if (was_max_horz
&& !moveresize_client
->max_horz
) {
1007 /* remax horz and put the premax back */
1008 client_maximize(moveresize_client
, TRUE
, 1);
1009 moveresize_client
->pre_max_area
.x
= pre_max_area
.x
;
1010 moveresize_client
->pre_max_area
.width
= pre_max_area
.width
;
1013 if (ABS(dh
) >= config_resist_edge
) {
1014 if (moveresize_client
->max_vert
) {
1016 was_max_vert
= TRUE
;
1017 pre_max_area
.y
= moveresize_client
->pre_max_area
.y
;
1018 pre_max_area
.height
=
1019 moveresize_client
->pre_max_area
.height
;
1021 moveresize_client
->pre_max_area
.y
= cur_y
;
1022 moveresize_client
->pre_max_area
.height
= cur_h
;
1023 client_maximize(moveresize_client
, FALSE
, 2);
1026 else if (was_max_vert
&& !moveresize_client
->max_vert
) {
1027 /* remax vert and put the premax back */
1028 client_maximize(moveresize_client
, TRUE
, 2);
1029 moveresize_client
->pre_max_area
.y
= pre_max_area
.y
;
1030 moveresize_client
->pre_max_area
.height
= pre_max_area
.height
;
1033 dw
-= cur_w
- start_cw
;
1034 dh
-= cur_h
- start_ch
;
1036 calc_resize(FALSE
, 0, &dw
, &dh
, dir
);
1040 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
1041 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
) ||
1042 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
))
1046 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
1047 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
) ||
1048 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
))
1056 } else if (e
->type
== KeyPress
) {
1057 KeySym sym
= obt_keyboard_keypress_to_keysym(e
);
1059 if (sym
== XK_Escape
) {
1060 moveresize_end(TRUE
);
1062 } else if (sym
== XK_Return
|| sym
== XK_KP_Enter
) {
1063 moveresize_end(FALSE
);
1065 } else if (sym
== XK_Right
|| sym
== XK_Left
||
1066 sym
== XK_Up
|| sym
== XK_Down
)
1068 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
1069 resize_with_keys(sym
, e
->xkey
.state
);
1071 } else if (corner
==
1072 OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
))
1074 move_with_keys(sym
, e
->xkey
.state
);
1080 else if (e
->type
== obt_display_extension_sync_basep
+ XSyncAlarmNotify
)
1082 waiting_for_sync
= 0; /* we got our sync... */
1083 do_resize(); /* ...so try resize if there is more change pending */
1088 if (used
&& moveresize_client
== focus_client
)
1089 event_update_user_time();