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 /* starting geometry for the window being moved/resized, so it can be
56 static gint start_x
, start_y
, start_cx
, start_cy
, start_cw
, start_ch
;
57 static gboolean was_max_horz
, was_max_vert
;
58 static Rect pre_max_area
;
59 static gint cur_x
, cur_y
, cur_w
, cur_h
;
61 static guint32 corner
;
62 static ObDirection edge_warp_dir
= -1;
63 static gboolean edge_warp_odd
= FALSE
;
64 static guint edge_warp_timer
= 0;
65 static ObDirection key_resize_edge
= -1;
67 static guint waiting_for_sync
;
68 static guint sync_timer
= 0;
71 static ObPopup
*popup
= NULL
;
73 static void do_move(gboolean keyboard
, gint keydist
);
74 static void do_resize(void);
75 static void do_edge_warp(gint x
, gint y
);
76 static void cancel_edge_warp();
78 static gboolean
sync_timeout_func(gpointer data
);
81 static void client_dest(ObClient
*client
, gpointer data
)
83 if (moveresize_client
== client
)
87 void moveresize_startup(gboolean reconfig
)
90 popup_set_text_align(popup
, RR_JUSTIFY_CENTER
);
93 client_add_destroy_notify(client_dest
, NULL
);
96 void moveresize_shutdown(gboolean reconfig
)
99 if (moveresize_in_progress
)
100 moveresize_end(FALSE
);
101 client_remove_destroy_notify(client_dest
);
108 static void popup_coords(ObClient
*c
, const gchar
*format
, gint a
, gint b
)
112 text
= g_strdup_printf(format
, a
, b
);
113 if (config_resize_popup_pos
== OB_RESIZE_POS_TOP
)
114 popup_position(popup
, SouthGravity
,
116 + c
->frame
->area
.width
/2,
117 c
->frame
->area
.y
- ob_rr_theme
->fbwidth
);
118 else if (config_resize_popup_pos
== OB_RESIZE_POS_CENTER
)
119 popup_position(popup
, CenterGravity
,
120 c
->frame
->area
.x
+ c
->frame
->area
.width
/ 2,
121 c
->frame
->area
.y
+ c
->frame
->area
.height
/ 2);
123 const Rect
*area
= screen_physical_area_active();
126 x
= config_resize_popup_fixed
.x
.pos
;
127 if (config_resize_popup_fixed
.x
.center
)
128 x
= area
->x
+ area
->width
/2;
129 else if (config_resize_popup_fixed
.x
.opposite
)
130 x
= RECT_RIGHT(*area
) - x
;
134 y
= config_resize_popup_fixed
.y
.pos
;
135 if (config_resize_popup_fixed
.y
.center
)
136 y
= area
->y
+ area
->height
/2;
137 else if (config_resize_popup_fixed
.y
.opposite
)
138 y
= RECT_RIGHT(*area
) - y
;
142 if (config_resize_popup_fixed
.x
.center
) {
143 if (config_resize_popup_fixed
.y
.center
)
144 gravity
= CenterGravity
;
145 else if (config_resize_popup_fixed
.y
.opposite
)
146 gravity
= SouthGravity
;
148 gravity
= NorthGravity
;
150 else if (config_resize_popup_fixed
.x
.opposite
) {
151 if (config_resize_popup_fixed
.y
.center
)
152 gravity
= EastGravity
;
153 else if (config_resize_popup_fixed
.y
.opposite
)
154 gravity
= SouthEastGravity
;
156 gravity
= NorthEastGravity
;
159 if (config_resize_popup_fixed
.y
.center
)
160 gravity
= WestGravity
;
161 else if (config_resize_popup_fixed
.y
.opposite
)
162 gravity
= SouthWestGravity
;
164 gravity
= NorthWestGravity
;
167 popup_position(popup
, gravity
, x
, y
);
169 popup_show(popup
, text
);
173 void moveresize_start(ObClient
*c
, gint x
, gint y
, guint b
, guint32 cnr
)
176 gboolean mv
= (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE
) ||
177 cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
));
181 if (moveresize_in_progress
|| !c
->frame
->visible
||
183 (c
->functions
& OB_CLIENT_FUNC_MOVE
) :
184 (c
->functions
& OB_CLIENT_FUNC_RESIZE
)))
187 if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
)) {
188 cur
= OB_CURSOR_NORTHWEST
;
191 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
)) {
192 cur
= OB_CURSOR_NORTH
;
195 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
)) {
196 cur
= OB_CURSOR_NORTHEAST
;
199 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT
))
200 cur
= OB_CURSOR_EAST
;
201 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
))
202 cur
= OB_CURSOR_SOUTHEAST
;
203 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM
))
204 cur
= OB_CURSOR_SOUTH
;
205 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
)) {
206 cur
= OB_CURSOR_SOUTHWEST
;
209 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
)) {
210 cur
= OB_CURSOR_WEST
;
213 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
))
214 cur
= OB_CURSOR_SOUTHEAST
;
215 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE
))
216 cur
= OB_CURSOR_MOVE
;
217 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
))
218 cur
= OB_CURSOR_MOVE
;
220 g_assert_not_reached();
222 /* keep the pointer bounded to the screen for move/resize */
223 if (!grab_pointer(FALSE
, TRUE
, cur
))
225 if (!grab_keyboard()) {
230 frame_end_iconify_animation(c
->frame
);
233 moveresize_client
= c
;
234 start_cx
= c
->area
.x
;
235 start_cy
= c
->area
.y
;
236 start_cw
= c
->area
.width
;
237 start_ch
= c
->area
.height
;
238 /* these adjustments for the size_inc make resizing a terminal more
239 friendly. you essentially start the resize in the middle of the
240 increment instead of at 0, so you have to move half an increment
241 either way instead of a full increment one and 1 px the other. */
242 start_x
= x
- (mv
? 0 : left
* c
->size_inc
.width
/ 2);
243 start_y
= y
- (mv
? 0 : up
* c
->size_inc
.height
/ 2);
246 key_resize_edge
= -1;
248 /* default to not putting max back on cancel */
249 was_max_horz
= was_max_vert
= FALSE
;
252 have to change start_cx and start_cy if going to do this..
253 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
254 corner == prop_atoms.net_wm_moveresize_size_keyboard)
255 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
256 c->area.width / 2, c->area.height / 2);
264 moveresize_in_progress
= TRUE
;
267 if (config_resize_redraw
&& !moving
&& obt_display_extension_sync
&&
268 moveresize_client
->sync_request
&& moveresize_client
->sync_counter
&&
269 !moveresize_client
->not_responding
)
271 /* Initialize values for the resize syncing, and create an alarm for
272 the client's xsync counter */
275 XSyncAlarmAttributes aa
;
277 /* set the counter to an initial value */
278 XSyncIntToValue(&val
, 0);
279 XSyncSetCounter(obt_display
, moveresize_client
->sync_counter
, val
);
281 /* this will be incremented when we tell the client what we're
283 moveresize_client
->sync_counter_value
= 0;
285 /* the next sequence we're waiting for with the alarm */
286 XSyncIntToValue(&val
, 1);
288 /* set an alarm on the counter */
289 aa
.trigger
.counter
= moveresize_client
->sync_counter
;
290 aa
.trigger
.wait_value
= val
;
291 aa
.trigger
.value_type
= XSyncAbsolute
;
292 aa
.trigger
.test_type
= XSyncPositiveTransition
;
294 XSyncIntToValue(&aa
.delta
, 1);
295 moveresize_alarm
= XSyncCreateAlarm(obt_display
,
304 waiting_for_sync
= 0;
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 */
467 if (waiting_for_sync
> SYNC_TIMEOUTS
) {
469 return FALSE
; /* don't repeat */
472 return TRUE
; /* keep waiting */
476 static void calc_resize(gboolean keyboard
, gint keydist
, gint
*dw
, gint
*dh
,
479 gint resist
, x
= 0, y
= 0, lw
, lh
, ow
, oh
, nw
, nh
;
488 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
491 case OB_DIRECTION_NORTH
:
492 case OB_DIRECTION_SOUTH
:
493 /* resize the width based on the height */
494 if (moveresize_client
->min_ratio
) {
495 if (nh
* moveresize_client
->min_ratio
> nw
)
496 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
498 if (moveresize_client
->max_ratio
) {
499 if (nh
* moveresize_client
->max_ratio
< nw
)
500 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
504 /* resize the height based on the width */
505 if (moveresize_client
->min_ratio
) {
506 if (nh
* moveresize_client
->min_ratio
> nw
)
507 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
509 if (moveresize_client
->max_ratio
) {
510 if (nh
* moveresize_client
->max_ratio
< nw
)
511 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
516 /* see its actual size (apply aspect ratios) */
517 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
,
523 /* resist_size_* needs the frame size */
524 nw
+= moveresize_client
->frame
->size
.left
+
525 moveresize_client
->frame
->size
.right
;
526 nh
+= moveresize_client
->frame
->size
.top
+
527 moveresize_client
->frame
->size
.bottom
;
529 if (keyboard
) resist
= keydist
- 1; /* resist for one key press */
530 else resist
= config_resist_win
;
531 resist_size_windows(moveresize_client
, resist
, &nw
, &nh
, dir
);
532 if (!keyboard
) resist
= config_resist_edge
;
533 resist_size_monitors(moveresize_client
, resist
, &nw
, &nh
, dir
);
535 nw
-= moveresize_client
->frame
->size
.left
+
536 moveresize_client
->frame
->size
.right
;
537 nh
-= moveresize_client
->frame
->size
.top
+
538 moveresize_client
->frame
->size
.bottom
;
543 /* take aspect ratios into account for resistance */
545 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
547 if (*dh
!= trydh
) { /* got resisted */
548 /* resize the width based on the height */
549 if (moveresize_client
->min_ratio
) {
550 if (nh
* moveresize_client
->min_ratio
> nw
)
551 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
553 if (moveresize_client
->max_ratio
) {
554 if (nh
* moveresize_client
->max_ratio
< nw
)
555 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
558 if (*dw
!= trydw
) { /* got resisted */
559 /* resize the height based on the width */
560 if (moveresize_client
->min_ratio
) {
561 if (nh
* moveresize_client
->min_ratio
> nw
)
562 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
564 if (moveresize_client
->max_ratio
) {
565 if (nh
* moveresize_client
->max_ratio
< nw
)
566 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
571 /* make sure it's all valid */
572 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
578 static void edge_warp_move_ptr(void)
583 screen_pointer_pos(&x
, &y
);
584 a
= screen_physical_area_all_monitors();
586 switch (edge_warp_dir
) {
587 case OB_DIRECTION_NORTH
:
590 case OB_DIRECTION_EAST
:
593 case OB_DIRECTION_SOUTH
:
596 case OB_DIRECTION_WEST
:
600 g_assert_not_reached();
603 XWarpPointer(obt_display
, 0, obt_root(ob_screen
), 0, 0, 0, 0, x
, y
);
606 static gboolean
edge_warp_delay_func(gpointer data
)
610 /* only fire every second time. so it's fast the first time, but slower
613 d
= screen_find_desktop(screen_desktop
, edge_warp_dir
, TRUE
, FALSE
);
614 if (d
!= screen_desktop
) {
615 if (config_mouse_screenedgewarp
) edge_warp_move_ptr();
616 screen_set_desktop(d
, TRUE
);
619 edge_warp_odd
= !edge_warp_odd
;
622 return TRUE
; /* do repeat ! */
625 static void do_edge_warp(gint x
, gint y
)
630 if (!config_mouse_screenedgetime
) return;
634 for (i
= 0; i
< screen_num_monitors
; ++i
) {
635 const Rect
*a
= screen_physical_area_monitor(i
);
636 if (x
== RECT_LEFT(*a
)) dir
= OB_DIRECTION_WEST
;
637 if (x
== RECT_RIGHT(*a
)) dir
= OB_DIRECTION_EAST
;
638 if (y
== RECT_TOP(*a
)) dir
= OB_DIRECTION_NORTH
;
639 if (y
== RECT_BOTTOM(*a
)) dir
= OB_DIRECTION_SOUTH
;
641 /* try check for xinerama boundaries */
642 if ((x
+ 1 == RECT_LEFT(*a
) || x
- 1 == RECT_RIGHT(*a
)) &&
643 (dir
== OB_DIRECTION_WEST
|| dir
== OB_DIRECTION_EAST
))
647 if ((y
+ 1 == RECT_TOP(*a
) || y
- 1 == RECT_BOTTOM(*a
)) &&
648 (dir
== OB_DIRECTION_NORTH
|| dir
== OB_DIRECTION_SOUTH
))
654 if (dir
!= edge_warp_dir
) {
656 if (dir
!= (ObDirection
)-1) {
657 edge_warp_odd
= TRUE
; /* switch on the first timeout */
658 edge_warp_timer
= g_timeout_add(config_mouse_screenedgetime
,
659 edge_warp_delay_func
, NULL
);
665 static void cancel_edge_warp(void)
667 if (edge_warp_timer
) g_source_remove(edge_warp_timer
);
671 static void move_with_keys(KeySym sym
, guint state
)
673 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
674 gint opx
, px
, opy
, py
;
677 /* shift means jump to edge */
678 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
))
684 dir
= OB_DIRECTION_EAST
;
685 else if (sym
== XK_Left
)
686 dir
= OB_DIRECTION_WEST
;
687 else if (sym
== XK_Down
)
688 dir
= OB_DIRECTION_SOUTH
;
689 else /* sym == XK_Up */
690 dir
= OB_DIRECTION_NORTH
;
692 client_find_move_directional(moveresize_client
, dir
, &x
, &y
);
693 dx
= x
- moveresize_client
->area
.x
;
694 dy
= y
- moveresize_client
->area
.y
;
696 /* control means fine grained */
698 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
707 else if (sym
== XK_Left
)
709 else if (sym
== XK_Down
)
711 else /* if (sym == XK_Up) */
715 screen_pointer_pos(&opx
, &opy
);
716 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
717 /* steal the motion events this causes */
718 XSync(obt_display
, FALSE
);
721 while (xqueue_remove_local(&ce
, xqueue_match_type
,
722 GINT_TO_POINTER(MotionNotify
)));
724 screen_pointer_pos(&px
, &py
);
730 /* because the cursor moves even though the window does
731 not nessesarily (resistance), this adjusts where the curor
732 thinks it started so that it keeps up with where the window
734 start_x
+= (px
- opx
) - (cur_x
- ox
);
735 start_y
+= (py
- opy
) - (cur_y
- oy
);
738 static void resize_with_keys(KeySym sym
, guint state
)
740 gint dw
= 0, dh
= 0, pdx
= 0, pdy
= 0, opx
, opy
, px
, py
;
744 /* pick the edge if it needs to move */
745 if (sym
== XK_Right
) {
746 dir
= OB_DIRECTION_EAST
;
747 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
748 key_resize_edge
!= OB_DIRECTION_EAST
)
750 key_resize_edge
= OB_DIRECTION_EAST
;
753 } else if (sym
== XK_Left
) {
754 dir
= OB_DIRECTION_WEST
;
755 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
756 key_resize_edge
!= OB_DIRECTION_EAST
)
758 key_resize_edge
= OB_DIRECTION_WEST
;
761 } else if (sym
== XK_Up
) {
762 dir
= OB_DIRECTION_NORTH
;
763 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
764 key_resize_edge
!= OB_DIRECTION_SOUTH
)
766 key_resize_edge
= OB_DIRECTION_NORTH
;
769 } else /* if (sym == XK_Down) */ {
770 dir
= OB_DIRECTION_SOUTH
;
771 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
772 key_resize_edge
!= OB_DIRECTION_SOUTH
)
774 key_resize_edge
= OB_DIRECTION_SOUTH
;
779 /* shift means jump to edge */
780 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
))
785 dir
= OB_DIRECTION_EAST
;
786 else if (sym
== XK_Left
)
787 dir
= OB_DIRECTION_WEST
;
788 else if (sym
== XK_Down
)
789 dir
= OB_DIRECTION_SOUTH
;
790 else /* if (sym == XK_Up)) */
791 dir
= OB_DIRECTION_NORTH
;
793 client_find_resize_directional(moveresize_client
, key_resize_edge
,
794 key_resize_edge
== dir
,
796 dw
= w
- moveresize_client
->area
.width
;
797 dh
= h
- moveresize_client
->area
.height
;
801 /* control means fine grained */
802 if (moveresize_client
->size_inc
.width
> 1) {
803 distw
= moveresize_client
->size_inc
.width
;
807 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
816 if (moveresize_client
->size_inc
.height
> 1) {
817 disth
= moveresize_client
->size_inc
.height
;
821 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
831 if (key_resize_edge
== OB_DIRECTION_WEST
) {
832 if (dir
== OB_DIRECTION_WEST
)
837 else if (key_resize_edge
== OB_DIRECTION_EAST
) {
838 if (dir
== OB_DIRECTION_EAST
)
843 else if (key_resize_edge
== OB_DIRECTION_NORTH
) {
844 if (dir
== OB_DIRECTION_NORTH
)
849 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
850 if (dir
== OB_DIRECTION_SOUTH
)
857 if (moveresize_client
->max_horz
&&
858 (key_resize_edge
== OB_DIRECTION_WEST
||
859 key_resize_edge
== OB_DIRECTION_EAST
))
863 pre_max_area
.x
= moveresize_client
->pre_max_area
.x
;
864 pre_max_area
.width
= moveresize_client
->pre_max_area
.width
;
866 moveresize_client
->pre_max_area
.x
= cur_x
;
867 moveresize_client
->pre_max_area
.width
= cur_w
;
868 client_maximize(moveresize_client
, FALSE
, 1);
870 else if (moveresize_client
->max_vert
&&
871 (key_resize_edge
== OB_DIRECTION_NORTH
||
872 key_resize_edge
== OB_DIRECTION_SOUTH
))
876 pre_max_area
.y
= moveresize_client
->pre_max_area
.y
;
877 pre_max_area
.height
= moveresize_client
->pre_max_area
.height
;
879 moveresize_client
->pre_max_area
.y
= cur_y
;
880 moveresize_client
->pre_max_area
.height
= cur_h
;
881 client_maximize(moveresize_client
, FALSE
, 2);
884 calc_resize(TRUE
, resist
, &dw
, &dh
, dir
);
885 if (key_resize_edge
== OB_DIRECTION_WEST
)
887 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
892 /* how to move the pointer to keep up with the change */
893 if (key_resize_edge
== OB_DIRECTION_WEST
)
895 else if (key_resize_edge
== OB_DIRECTION_EAST
)
897 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
899 else if (key_resize_edge
== OB_DIRECTION_SOUTH
)
902 screen_pointer_pos(&opx
, &opy
);
903 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, pdx
, pdy
);
904 /* steal the motion events this causes */
905 XSync(obt_display
, FALSE
);
908 while (xqueue_remove_local(&ce
, xqueue_match_type
,
909 GINT_TO_POINTER(MotionNotify
)));
911 screen_pointer_pos(&px
, &py
);
915 /* because the cursor moves even though the window does
916 not nessesarily (resistance), this adjusts where the cursor
917 thinks it started so that it keeps up with where the window
919 start_x
+= (px
- opx
) - dw
;
920 start_y
+= (py
- opy
) - dh
;
924 gboolean
moveresize_event(XEvent
*e
)
926 gboolean used
= FALSE
;
928 if (!moveresize_in_progress
) return FALSE
;
930 if (e
->type
== ButtonPress
) {
932 start_x
= e
->xbutton
.x_root
;
933 start_y
= e
->xbutton
.y_root
;
934 button
= e
->xbutton
.button
; /* this will end it now */
936 used
= e
->xbutton
.button
== button
;
937 } else if (e
->type
== ButtonRelease
) {
938 if (!button
|| e
->xbutton
.button
== button
) {
939 moveresize_end(FALSE
);
942 } else if (e
->type
== MotionNotify
) {
944 cur_x
= start_cx
+ e
->xmotion
.x_root
- start_x
;
945 cur_y
= start_cy
+ e
->xmotion
.y_root
- start_y
;
947 do_edge_warp(e
->xmotion
.x_root
, e
->xmotion
.y_root
);
952 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
)) {
953 dw
= -(e
->xmotion
.x_root
- start_x
);
954 dh
= -(e
->xmotion
.y_root
- start_y
);
955 dir
= OB_DIRECTION_NORTHWEST
;
956 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
)) {
958 dh
= -(e
->xmotion
.y_root
- start_y
);
959 dir
= OB_DIRECTION_NORTH
;
961 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
)) {
962 dw
= (e
->xmotion
.x_root
- start_x
);
963 dh
= -(e
->xmotion
.y_root
- start_y
);
964 dir
= OB_DIRECTION_NORTHEAST
;
965 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT
)) {
966 dw
= (e
->xmotion
.x_root
- start_x
);
968 dir
= OB_DIRECTION_EAST
;
970 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
)) {
971 dw
= (e
->xmotion
.x_root
- start_x
);
972 dh
= (e
->xmotion
.y_root
- start_y
);
973 dir
= OB_DIRECTION_SOUTHEAST
;
974 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM
))
977 dh
= (e
->xmotion
.y_root
- start_y
);
978 dir
= OB_DIRECTION_SOUTH
;
980 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
)) {
981 dw
= -(e
->xmotion
.x_root
- start_x
);
982 dh
= (e
->xmotion
.y_root
- start_y
);
983 dir
= OB_DIRECTION_SOUTHWEST
;
984 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
)) {
985 dw
= -(e
->xmotion
.x_root
- start_x
);
987 dir
= OB_DIRECTION_WEST
;
989 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
990 dw
= (e
->xmotion
.x_root
- start_x
);
991 dh
= (e
->xmotion
.y_root
- start_y
);
992 dir
= OB_DIRECTION_SOUTHEAST
;
994 g_assert_not_reached();
996 /* override the client's max state if desired */
997 if (ABS(dw
) >= config_resist_edge
) {
998 if (moveresize_client
->max_horz
) {
1000 was_max_horz
= TRUE
;
1001 pre_max_area
.x
= moveresize_client
->pre_max_area
.x
;
1002 pre_max_area
.width
= moveresize_client
->pre_max_area
.width
;
1004 moveresize_client
->pre_max_area
.x
= cur_x
;
1005 moveresize_client
->pre_max_area
.width
= cur_w
;
1006 client_maximize(moveresize_client
, FALSE
, 1);
1009 else if (was_max_horz
&& !moveresize_client
->max_horz
) {
1010 /* remax horz and put the premax back */
1011 client_maximize(moveresize_client
, TRUE
, 1);
1012 moveresize_client
->pre_max_area
.x
= pre_max_area
.x
;
1013 moveresize_client
->pre_max_area
.width
= pre_max_area
.width
;
1016 if (ABS(dh
) >= config_resist_edge
) {
1017 if (moveresize_client
->max_vert
) {
1019 was_max_vert
= TRUE
;
1020 pre_max_area
.y
= moveresize_client
->pre_max_area
.y
;
1021 pre_max_area
.height
=
1022 moveresize_client
->pre_max_area
.height
;
1024 moveresize_client
->pre_max_area
.y
= cur_y
;
1025 moveresize_client
->pre_max_area
.height
= cur_h
;
1026 client_maximize(moveresize_client
, FALSE
, 2);
1029 else if (was_max_vert
&& !moveresize_client
->max_vert
) {
1030 /* remax vert and put the premax back */
1031 client_maximize(moveresize_client
, TRUE
, 2);
1032 moveresize_client
->pre_max_area
.y
= pre_max_area
.y
;
1033 moveresize_client
->pre_max_area
.height
= pre_max_area
.height
;
1036 dw
-= cur_w
- start_cw
;
1037 dh
-= cur_h
- start_ch
;
1039 calc_resize(FALSE
, 0, &dw
, &dh
, dir
);
1043 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
1044 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
) ||
1045 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
))
1049 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
1050 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
) ||
1051 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
))
1059 } else if (e
->type
== KeyPress
) {
1060 KeySym sym
= obt_keyboard_keypress_to_keysym(e
);
1062 if (sym
== XK_Escape
) {
1063 moveresize_end(TRUE
);
1065 } else if (sym
== XK_Return
|| sym
== XK_KP_Enter
) {
1066 moveresize_end(FALSE
);
1068 } else if (sym
== XK_Right
|| sym
== XK_Left
||
1069 sym
== XK_Up
|| sym
== XK_Down
)
1071 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
1072 resize_with_keys(sym
, e
->xkey
.state
);
1074 } else if (corner
==
1075 OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
))
1077 move_with_keys(sym
, e
->xkey
.state
);
1083 else if (e
->type
== obt_display_extension_sync_basep
+ XSyncAlarmNotify
)
1085 waiting_for_sync
= 0; /* we got our sync... */
1086 do_resize(); /* ...so try resize if there is more change pending */