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
)
86 if (popup
&& client
== popup
->client
)
90 void moveresize_startup(gboolean reconfig
)
93 popup_set_text_align(popup
, RR_JUSTIFY_CENTER
);
96 client_add_destroy_notify(client_dest
, NULL
);
99 void moveresize_shutdown(gboolean reconfig
)
102 if (moveresize_in_progress
)
103 moveresize_end(FALSE
);
104 client_remove_destroy_notify(client_dest
);
111 static void popup_coords(ObClient
*c
, const gchar
*format
, gint a
, gint b
)
115 text
= g_strdup_printf(format
, a
, b
);
116 if (config_resize_popup_pos
== OB_RESIZE_POS_TOP
)
117 popup_position(popup
, SouthGravity
,
119 + c
->frame
->area
.width
/2,
120 c
->frame
->area
.y
- ob_rr_theme
->fbwidth
);
121 else if (config_resize_popup_pos
== OB_RESIZE_POS_CENTER
)
122 popup_position(popup
, CenterGravity
,
123 c
->frame
->area
.x
+ c
->frame
->area
.width
/ 2,
124 c
->frame
->area
.y
+ c
->frame
->area
.height
/ 2);
126 const Rect
*area
= screen_physical_area_active();
129 x
= config_resize_popup_fixed
.x
.pos
;
130 if (config_resize_popup_fixed
.x
.center
)
131 x
= area
->x
+ area
->width
/2;
132 else if (config_resize_popup_fixed
.x
.opposite
)
133 x
= RECT_RIGHT(*area
) - x
;
137 y
= config_resize_popup_fixed
.y
.pos
;
138 if (config_resize_popup_fixed
.y
.center
)
139 y
= area
->y
+ area
->height
/2;
140 else if (config_resize_popup_fixed
.y
.opposite
)
141 y
= RECT_RIGHT(*area
) - y
;
145 if (config_resize_popup_fixed
.x
.center
) {
146 if (config_resize_popup_fixed
.y
.center
)
147 gravity
= CenterGravity
;
148 else if (config_resize_popup_fixed
.y
.opposite
)
149 gravity
= SouthGravity
;
151 gravity
= NorthGravity
;
153 else if (config_resize_popup_fixed
.x
.opposite
) {
154 if (config_resize_popup_fixed
.y
.center
)
155 gravity
= EastGravity
;
156 else if (config_resize_popup_fixed
.y
.opposite
)
157 gravity
= SouthEastGravity
;
159 gravity
= NorthEastGravity
;
162 if (config_resize_popup_fixed
.y
.center
)
163 gravity
= WestGravity
;
164 else if (config_resize_popup_fixed
.y
.opposite
)
165 gravity
= SouthWestGravity
;
167 gravity
= NorthWestGravity
;
170 popup_position(popup
, gravity
, x
, y
);
173 popup_show(popup
, text
);
177 void moveresize_start(ObClient
*c
, gint x
, gint y
, guint b
, guint32 cnr
)
180 gboolean mv
= (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE
) ||
181 cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
));
185 if (moveresize_in_progress
|| !c
->frame
->visible
||
187 (c
->functions
& OB_CLIENT_FUNC_MOVE
) :
188 (c
->functions
& OB_CLIENT_FUNC_RESIZE
)))
191 if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
)) {
192 cur
= OB_CURSOR_NORTHWEST
;
195 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
)) {
196 cur
= OB_CURSOR_NORTH
;
199 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
)) {
200 cur
= OB_CURSOR_NORTHEAST
;
203 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT
))
204 cur
= OB_CURSOR_EAST
;
205 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
))
206 cur
= OB_CURSOR_SOUTHEAST
;
207 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM
))
208 cur
= OB_CURSOR_SOUTH
;
209 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
)) {
210 cur
= OB_CURSOR_SOUTHWEST
;
213 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
)) {
214 cur
= OB_CURSOR_WEST
;
217 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
))
218 cur
= OB_CURSOR_SOUTHEAST
;
219 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE
))
220 cur
= OB_CURSOR_MOVE
;
221 else if (cnr
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
))
222 cur
= OB_CURSOR_MOVE
;
224 g_assert_not_reached();
226 /* keep the pointer bounded to the screen for move/resize */
227 if (!grab_pointer(FALSE
, TRUE
, cur
))
229 if (!grab_keyboard()) {
234 frame_end_iconify_animation(c
->frame
);
237 moveresize_client
= c
;
238 start_cx
= c
->area
.x
;
239 start_cy
= c
->area
.y
;
240 start_cw
= c
->area
.width
;
241 start_ch
= c
->area
.height
;
242 /* these adjustments for the size_inc make resizing a terminal more
243 friendly. you essentially start the resize in the middle of the
244 increment instead of at 0, so you have to move half an increment
245 either way instead of a full increment one and 1 px the other. */
246 start_x
= x
- (mv
? 0 : left
* c
->size_inc
.width
/ 2);
247 start_y
= y
- (mv
? 0 : up
* c
->size_inc
.height
/ 2);
250 key_resize_edge
= -1;
252 /* default to not putting max back on cancel */
253 was_max_horz
= was_max_vert
= FALSE
;
256 have to change start_cx and start_cy if going to do this..
257 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
258 corner == prop_atoms.net_wm_moveresize_size_keyboard)
259 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
260 c->area.width / 2, c->area.height / 2);
268 moveresize_in_progress
= TRUE
;
269 waiting_for_sync
= 0;
272 if (config_resize_redraw
&& !moving
&& obt_display_extension_sync
&&
273 moveresize_client
->sync_request
&& moveresize_client
->sync_counter
&&
274 !moveresize_client
->not_responding
)
276 /* Initialize values for the resize syncing, and create an alarm for
277 the client's xsync counter */
280 XSyncAlarmAttributes aa
;
282 /* set the counter to an initial value */
283 XSyncIntToValue(&val
, 0);
284 XSyncSetCounter(obt_display
, moveresize_client
->sync_counter
, val
);
286 /* this will be incremented when we tell the client what we're
288 moveresize_client
->sync_counter_value
= 0;
290 /* the next sequence we're waiting for with the alarm */
291 XSyncIntToValue(&val
, 1);
293 /* set an alarm on the counter */
294 aa
.trigger
.counter
= moveresize_client
->sync_counter
;
295 aa
.trigger
.wait_value
= val
;
296 aa
.trigger
.value_type
= XSyncAbsolute
;
297 aa
.trigger
.test_type
= XSyncPositiveTransition
;
299 XSyncIntToValue(&aa
.delta
, 1);
300 moveresize_alarm
= XSyncCreateAlarm(obt_display
,
312 void moveresize_end(gboolean cancel
)
318 popup
->client
= NULL
;
322 /* turn off the alarm */
323 if (moveresize_alarm
!= None
) {
324 XSyncDestroyAlarm(obt_display
, moveresize_alarm
);
325 moveresize_alarm
= None
;
328 if (sync_timer
) g_source_remove(sync_timer
);
333 /* don't use client_move() here, use the same width/height as
334 we've been using during the move, otherwise we get different results
335 when moving maximized windows between monitors of different sizes !
337 client_configure(moveresize_client
,
338 (cancel
? start_cx
: cur_x
),
339 (cancel
? start_cy
: cur_y
),
340 (cancel
? start_cw
: cur_w
),
341 (cancel
? start_ch
: cur_h
),
344 /* restore the client's maximized state. do this after putting the window
345 back in its original spot to minimize visible flicker */
346 if (cancel
&& (was_max_horz
|| was_max_vert
)) {
347 const gboolean h
= moveresize_client
->max_horz
;
348 const gboolean v
= moveresize_client
->max_vert
;
350 client_maximize(moveresize_client
, TRUE
,
351 was_max_horz
&& was_max_vert
? 0 :
352 (was_max_horz
? 1 : 2));
354 /* replace the premax values with the ones we had saved if
355 the client doesn't have any already set */
356 if (was_max_horz
&& !h
) {
357 moveresize_client
->pre_max_area
.x
= pre_max_area
.x
;
358 moveresize_client
->pre_max_area
.width
= pre_max_area
.width
;
360 if (was_max_vert
&& !v
) {
361 moveresize_client
->pre_max_area
.y
= pre_max_area
.y
;
362 moveresize_client
->pre_max_area
.height
= pre_max_area
.height
;
366 /* dont edge warp after its ended */
369 moveresize_in_progress
= FALSE
;
370 moveresize_client
= NULL
;
373 static void do_move(gboolean keyboard
, gint keydist
)
377 if (keyboard
) resist
= keydist
- 1; /* resist for one key press */
378 else resist
= config_resist_win
;
379 resist_move_windows(moveresize_client
, resist
, &cur_x
, &cur_y
);
380 if (!keyboard
) resist
= config_resist_edge
;
381 resist_move_monitors(moveresize_client
, resist
, &cur_x
, &cur_y
);
383 client_configure(moveresize_client
, cur_x
, cur_y
, cur_w
, cur_h
,
385 if (config_resize_popup_show
== 2) /* == "Always" */
386 popup_coords(moveresize_client
, "%d x %d",
387 moveresize_client
->frame
->area
.x
,
388 moveresize_client
->frame
->area
.y
);
391 static void do_resize(void)
393 gint x
, y
, w
, h
, lw
, lh
;
395 /* see if it is actually going to resize
396 USE cur_x AND cur_y HERE ! Otherwise the try_configure won't know
397 what struts to use !!
403 client_try_configure(moveresize_client
, &x
, &y
, &w
, &h
,
405 if (!(w
== moveresize_client
->area
.width
&&
406 h
== moveresize_client
->area
.height
) &&
407 /* if waiting_for_sync == 0, then we aren't waiting.
408 if it is > SYNC_TIMEOUTS, then we have timed out
409 that many times already, so forget about waiting more */
410 (waiting_for_sync
== 0 || waiting_for_sync
> SYNC_TIMEOUTS
))
413 if (config_resize_redraw
&& obt_display_extension_sync
&&
414 /* don't send another sync when one is pending */
415 waiting_for_sync
== 0 &&
416 moveresize_client
->sync_request
&&
417 moveresize_client
->sync_counter
&&
418 !moveresize_client
->not_responding
)
423 /* increment the value we're waiting for */
424 ++moveresize_client
->sync_counter_value
;
425 XSyncIntToValue(&val
, moveresize_client
->sync_counter_value
);
427 /* tell the client what we're waiting for */
428 ce
.xclient
.type
= ClientMessage
;
429 ce
.xclient
.message_type
= OBT_PROP_ATOM(WM_PROTOCOLS
);
430 ce
.xclient
.display
= obt_display
;
431 ce
.xclient
.window
= moveresize_client
->window
;
432 ce
.xclient
.format
= 32;
433 ce
.xclient
.data
.l
[0] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST
);
434 ce
.xclient
.data
.l
[1] = event_time();
435 ce
.xclient
.data
.l
[2] = XSyncValueLow32(val
);
436 ce
.xclient
.data
.l
[3] = XSyncValueHigh32(val
);
437 ce
.xclient
.data
.l
[4] = 0l;
438 XSendEvent(obt_display
, moveresize_client
->window
, FALSE
,
441 waiting_for_sync
= 1;
443 if (sync_timer
) g_source_remove(sync_timer
);
444 sync_timer
= g_timeout_add(2000, sync_timeout_func
, NULL
);
448 /* force a ConfigureNotify, it is part of the spec for SYNC resizing
449 and MUST follow the sync counter notification */
450 client_configure(moveresize_client
, cur_x
, cur_y
, cur_w
, cur_h
,
454 /* this would be better with a fixed width font ... XXX can do it better
455 if there are 2 text boxes */
456 if (config_resize_popup_show
== 2 || /* == "Always" */
457 (config_resize_popup_show
== 1 && /* == "Nonpixel" */
458 moveresize_client
->size_inc
.width
> 1 &&
459 moveresize_client
->size_inc
.height
> 1))
460 popup_coords(moveresize_client
, "%d x %d", lw
, lh
);
464 static gboolean
sync_timeout_func(gpointer data
)
466 ++waiting_for_sync
; /* we timed out waiting for our sync... */
467 do_resize(); /* ...so let any pending resizes through */
469 if (waiting_for_sync
> SYNC_TIMEOUTS
) {
471 return FALSE
; /* don't repeat */
474 return TRUE
; /* keep waiting */
478 static void calc_resize(gboolean keyboard
, gint keydist
, gint
*dw
, gint
*dh
,
481 gint resist
, x
= 0, y
= 0, lw
, lh
, ow
, oh
, nw
, nh
;
490 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
493 case OB_DIRECTION_NORTH
:
494 case OB_DIRECTION_SOUTH
:
495 /* resize the width based on the height */
496 if (moveresize_client
->min_ratio
) {
497 if (nh
* moveresize_client
->min_ratio
> nw
)
498 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
500 if (moveresize_client
->max_ratio
) {
501 if (nh
* moveresize_client
->max_ratio
< nw
)
502 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
506 /* resize the height based on the width */
507 if (moveresize_client
->min_ratio
) {
508 if (nh
* moveresize_client
->min_ratio
> nw
)
509 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
511 if (moveresize_client
->max_ratio
) {
512 if (nh
* moveresize_client
->max_ratio
< nw
)
513 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
518 /* see its actual size (apply aspect ratios) */
519 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
,
525 /* resist_size_* needs the frame size */
526 nw
+= moveresize_client
->frame
->size
.left
+
527 moveresize_client
->frame
->size
.right
;
528 nh
+= moveresize_client
->frame
->size
.top
+
529 moveresize_client
->frame
->size
.bottom
;
531 if (keyboard
) resist
= keydist
- 1; /* resist for one key press */
532 else resist
= config_resist_win
;
533 resist_size_windows(moveresize_client
, resist
, &nw
, &nh
, dir
);
534 if (!keyboard
) resist
= config_resist_edge
;
535 resist_size_monitors(moveresize_client
, resist
, &nw
, &nh
, dir
);
537 nw
-= moveresize_client
->frame
->size
.left
+
538 moveresize_client
->frame
->size
.right
;
539 nh
-= moveresize_client
->frame
->size
.top
+
540 moveresize_client
->frame
->size
.bottom
;
545 /* take aspect ratios into account for resistance */
547 (moveresize_client
->max_ratio
|| moveresize_client
->min_ratio
))
549 if (*dh
!= trydh
) { /* got resisted */
550 /* resize the width based on the height */
551 if (moveresize_client
->min_ratio
) {
552 if (nh
* moveresize_client
->min_ratio
> nw
)
553 nw
= (gint
)(nh
* moveresize_client
->min_ratio
);
555 if (moveresize_client
->max_ratio
) {
556 if (nh
* moveresize_client
->max_ratio
< nw
)
557 nw
= (gint
)(nh
* moveresize_client
->max_ratio
);
560 if (*dw
!= trydw
) { /* got resisted */
561 /* resize the height based on the width */
562 if (moveresize_client
->min_ratio
) {
563 if (nh
* moveresize_client
->min_ratio
> nw
)
564 nh
= (gint
)(nw
/ moveresize_client
->min_ratio
);
566 if (moveresize_client
->max_ratio
) {
567 if (nh
* moveresize_client
->max_ratio
< nw
)
568 nh
= (gint
)(nw
/ moveresize_client
->max_ratio
);
573 /* make sure it's all valid */
574 client_try_configure(moveresize_client
, &x
, &y
, &nw
, &nh
, &lw
, &lh
, TRUE
);
580 static void edge_warp_move_ptr(void)
585 screen_pointer_pos(&x
, &y
);
586 a
= screen_physical_area_all_monitors();
588 switch (edge_warp_dir
) {
589 case OB_DIRECTION_NORTH
:
592 case OB_DIRECTION_EAST
:
595 case OB_DIRECTION_SOUTH
:
598 case OB_DIRECTION_WEST
:
602 g_assert_not_reached();
605 XWarpPointer(obt_display
, 0, obt_root(ob_screen
), 0, 0, 0, 0, x
, y
);
608 static gboolean
edge_warp_delay_func(gpointer data
)
612 /* only fire every second time. so it's fast the first time, but slower
615 d
= screen_find_desktop(screen_desktop
, edge_warp_dir
, TRUE
, FALSE
);
616 if (d
!= screen_desktop
) {
617 if (config_mouse_screenedgewarp
) edge_warp_move_ptr();
618 screen_set_desktop(d
, TRUE
);
621 edge_warp_odd
= !edge_warp_odd
;
623 return TRUE
; /* do repeat ! */
626 static void do_edge_warp(gint x
, gint y
)
631 if (!config_mouse_screenedgetime
) return;
635 for (i
= 0; i
< screen_num_monitors
; ++i
) {
636 const Rect
*a
= screen_physical_area_monitor(i
);
638 if (!RECT_CONTAINS(*a
, x
, y
))
641 if (x
== RECT_LEFT(*a
)) dir
= OB_DIRECTION_WEST
;
642 if (x
== RECT_RIGHT(*a
)) dir
= OB_DIRECTION_EAST
;
643 if (y
== RECT_TOP(*a
)) dir
= OB_DIRECTION_NORTH
;
644 if (y
== RECT_BOTTOM(*a
)) dir
= OB_DIRECTION_SOUTH
;
646 /* try check for xinerama boundaries */
647 if ((x
+ 1 == RECT_LEFT(*a
) || x
- 1 == RECT_RIGHT(*a
)) &&
648 (dir
== OB_DIRECTION_WEST
|| dir
== OB_DIRECTION_EAST
))
652 if ((y
+ 1 == RECT_TOP(*a
) || y
- 1 == RECT_BOTTOM(*a
)) &&
653 (dir
== OB_DIRECTION_NORTH
|| dir
== OB_DIRECTION_SOUTH
))
659 if (dir
!= edge_warp_dir
) {
661 if (dir
!= (ObDirection
)-1) {
662 edge_warp_odd
= TRUE
; /* switch on the first timeout */
663 edge_warp_timer
= g_timeout_add(config_mouse_screenedgetime
,
664 edge_warp_delay_func
, NULL
);
670 static void cancel_edge_warp(void)
672 if (edge_warp_timer
) g_source_remove(edge_warp_timer
);
676 static void move_with_keys(KeySym sym
, guint state
)
678 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
679 gint opx
, px
, opy
, py
;
682 /* shift means jump to edge */
683 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
))
689 dir
= OB_DIRECTION_EAST
;
690 else if (sym
== XK_Left
)
691 dir
= OB_DIRECTION_WEST
;
692 else if (sym
== XK_Down
)
693 dir
= OB_DIRECTION_SOUTH
;
694 else /* sym == XK_Up */
695 dir
= OB_DIRECTION_NORTH
;
697 client_find_move_directional(moveresize_client
, dir
, &x
, &y
);
698 dx
= x
- moveresize_client
->area
.x
;
699 dy
= y
- moveresize_client
->area
.y
;
701 /* control means fine grained */
703 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
712 else if (sym
== XK_Left
)
714 else if (sym
== XK_Down
)
716 else /* if (sym == XK_Up) */
720 screen_pointer_pos(&opx
, &opy
);
721 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
722 /* steal the motion events this causes */
723 XSync(obt_display
, FALSE
);
726 while (xqueue_remove_local(&ce
, xqueue_match_type
,
727 GINT_TO_POINTER(MotionNotify
)));
729 screen_pointer_pos(&px
, &py
);
735 /* because the cursor moves even though the window does
736 not nessesarily (resistance), this adjusts where the curor
737 thinks it started so that it keeps up with where the window
739 start_x
+= (px
- opx
) - (cur_x
- ox
);
740 start_y
+= (py
- opy
) - (cur_y
- oy
);
743 static void resize_with_keys(KeySym sym
, guint state
)
745 gint dw
= 0, dh
= 0, pdx
= 0, pdy
= 0, opx
, opy
, px
, py
;
749 /* pick the edge if it needs to move */
750 if (sym
== XK_Right
) {
751 dir
= OB_DIRECTION_EAST
;
752 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
753 key_resize_edge
!= OB_DIRECTION_EAST
)
755 key_resize_edge
= OB_DIRECTION_EAST
;
758 } else if (sym
== XK_Left
) {
759 dir
= OB_DIRECTION_WEST
;
760 if (key_resize_edge
!= OB_DIRECTION_WEST
&&
761 key_resize_edge
!= OB_DIRECTION_EAST
)
763 key_resize_edge
= OB_DIRECTION_WEST
;
766 } else if (sym
== XK_Up
) {
767 dir
= OB_DIRECTION_NORTH
;
768 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
769 key_resize_edge
!= OB_DIRECTION_SOUTH
)
771 key_resize_edge
= OB_DIRECTION_NORTH
;
774 } else /* if (sym == XK_Down) */ {
775 dir
= OB_DIRECTION_SOUTH
;
776 if (key_resize_edge
!= OB_DIRECTION_NORTH
&&
777 key_resize_edge
!= OB_DIRECTION_SOUTH
)
779 key_resize_edge
= OB_DIRECTION_SOUTH
;
784 /* shift means jump to edge */
785 if (state
& obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT
))
790 dir
= OB_DIRECTION_EAST
;
791 else if (sym
== XK_Left
)
792 dir
= OB_DIRECTION_WEST
;
793 else if (sym
== XK_Down
)
794 dir
= OB_DIRECTION_SOUTH
;
795 else /* if (sym == XK_Up)) */
796 dir
= OB_DIRECTION_NORTH
;
798 ObClientDirectionalResizeType resize_type
=
799 key_resize_edge
== dir
? CLIENT_RESIZE_GROW
800 : CLIENT_RESIZE_SHRINK
;
802 client_find_resize_directional(moveresize_client
,
806 dw
= w
- moveresize_client
->area
.width
;
807 dh
= h
- moveresize_client
->area
.height
;
811 /* control means fine grained */
812 if (moveresize_client
->size_inc
.width
> 1) {
813 distw
= moveresize_client
->size_inc
.width
;
817 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
826 if (moveresize_client
->size_inc
.height
> 1) {
827 disth
= moveresize_client
->size_inc
.height
;
831 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL
))
841 if (key_resize_edge
== OB_DIRECTION_WEST
) {
842 if (dir
== OB_DIRECTION_WEST
)
847 else if (key_resize_edge
== OB_DIRECTION_EAST
) {
848 if (dir
== OB_DIRECTION_EAST
)
853 else if (key_resize_edge
== OB_DIRECTION_NORTH
) {
854 if (dir
== OB_DIRECTION_NORTH
)
859 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
860 if (dir
== OB_DIRECTION_SOUTH
)
867 if (moveresize_client
->max_horz
&&
868 (key_resize_edge
== OB_DIRECTION_WEST
||
869 key_resize_edge
== OB_DIRECTION_EAST
))
873 pre_max_area
.x
= moveresize_client
->pre_max_area
.x
;
874 pre_max_area
.width
= moveresize_client
->pre_max_area
.width
;
876 moveresize_client
->pre_max_area
.x
= cur_x
;
877 moveresize_client
->pre_max_area
.width
= cur_w
;
878 client_maximize(moveresize_client
, FALSE
, 1);
880 else if (moveresize_client
->max_vert
&&
881 (key_resize_edge
== OB_DIRECTION_NORTH
||
882 key_resize_edge
== OB_DIRECTION_SOUTH
))
886 pre_max_area
.y
= moveresize_client
->pre_max_area
.y
;
887 pre_max_area
.height
= moveresize_client
->pre_max_area
.height
;
889 moveresize_client
->pre_max_area
.y
= cur_y
;
890 moveresize_client
->pre_max_area
.height
= cur_h
;
891 client_maximize(moveresize_client
, FALSE
, 2);
894 calc_resize(TRUE
, resist
, &dw
, &dh
, dir
);
895 if (key_resize_edge
== OB_DIRECTION_WEST
)
897 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
902 /* how to move the pointer to keep up with the change */
903 if (key_resize_edge
== OB_DIRECTION_WEST
)
905 else if (key_resize_edge
== OB_DIRECTION_EAST
)
907 else if (key_resize_edge
== OB_DIRECTION_NORTH
)
909 else if (key_resize_edge
== OB_DIRECTION_SOUTH
)
912 screen_pointer_pos(&opx
, &opy
);
913 XWarpPointer(obt_display
, None
, None
, 0, 0, 0, 0, pdx
, pdy
);
914 /* steal the motion events this causes */
915 XSync(obt_display
, FALSE
);
918 while (xqueue_remove_local(&ce
, xqueue_match_type
,
919 GINT_TO_POINTER(MotionNotify
)));
921 screen_pointer_pos(&px
, &py
);
925 /* because the cursor moves even though the window does
926 not nessesarily (resistance), this adjusts where the cursor
927 thinks it started so that it keeps up with where the window
929 start_x
+= (px
- opx
) - dw
;
930 start_y
+= (py
- opy
) - dh
;
934 gboolean
moveresize_event(XEvent
*e
)
936 gboolean used
= FALSE
;
938 if (!moveresize_in_progress
) return FALSE
;
940 if (e
->type
== ButtonPress
) {
942 start_x
= e
->xbutton
.x_root
;
943 start_y
= e
->xbutton
.y_root
;
944 button
= e
->xbutton
.button
; /* this will end it now */
946 used
= e
->xbutton
.button
== button
;
947 } else if (e
->type
== ButtonRelease
) {
948 if (!button
|| e
->xbutton
.button
== button
) {
949 moveresize_end(FALSE
);
952 } else if (e
->type
== MotionNotify
) {
954 cur_x
= start_cx
+ e
->xmotion
.x_root
- start_x
;
955 cur_y
= start_cy
+ e
->xmotion
.y_root
- start_y
;
957 do_edge_warp(e
->xmotion
.x_root
, e
->xmotion
.y_root
);
962 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
)) {
963 dw
= -(e
->xmotion
.x_root
- start_x
);
964 dh
= -(e
->xmotion
.y_root
- start_y
);
965 dir
= OB_DIRECTION_NORTHWEST
;
966 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
)) {
968 dh
= -(e
->xmotion
.y_root
- start_y
);
969 dir
= OB_DIRECTION_NORTH
;
971 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
)) {
972 dw
= (e
->xmotion
.x_root
- start_x
);
973 dh
= -(e
->xmotion
.y_root
- start_y
);
974 dir
= OB_DIRECTION_NORTHEAST
;
975 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT
)) {
976 dw
= (e
->xmotion
.x_root
- start_x
);
978 dir
= OB_DIRECTION_EAST
;
980 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
)) {
981 dw
= (e
->xmotion
.x_root
- start_x
);
982 dh
= (e
->xmotion
.y_root
- start_y
);
983 dir
= OB_DIRECTION_SOUTHEAST
;
984 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM
))
987 dh
= (e
->xmotion
.y_root
- start_y
);
988 dir
= OB_DIRECTION_SOUTH
;
990 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
)) {
991 dw
= -(e
->xmotion
.x_root
- start_x
);
992 dh
= (e
->xmotion
.y_root
- start_y
);
993 dir
= OB_DIRECTION_SOUTHWEST
;
994 } else if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
)) {
995 dw
= -(e
->xmotion
.x_root
- start_x
);
997 dir
= OB_DIRECTION_WEST
;
999 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
1000 dw
= (e
->xmotion
.x_root
- start_x
);
1001 dh
= (e
->xmotion
.y_root
- start_y
);
1002 dir
= OB_DIRECTION_SOUTHEAST
;
1004 g_assert_not_reached();
1006 /* override the client's max state if desired */
1007 if (ABS(dw
) >= config_resist_edge
) {
1008 if (moveresize_client
->max_horz
) {
1010 was_max_horz
= TRUE
;
1011 pre_max_area
.x
= moveresize_client
->pre_max_area
.x
;
1012 pre_max_area
.width
= moveresize_client
->pre_max_area
.width
;
1014 moveresize_client
->pre_max_area
.x
= cur_x
;
1015 moveresize_client
->pre_max_area
.width
= cur_w
;
1016 client_maximize(moveresize_client
, FALSE
, 1);
1019 else if (was_max_horz
&& !moveresize_client
->max_horz
) {
1020 /* remax horz and put the premax back */
1021 client_maximize(moveresize_client
, TRUE
, 1);
1022 moveresize_client
->pre_max_area
.x
= pre_max_area
.x
;
1023 moveresize_client
->pre_max_area
.width
= pre_max_area
.width
;
1026 if (ABS(dh
) >= config_resist_edge
) {
1027 if (moveresize_client
->max_vert
) {
1029 was_max_vert
= TRUE
;
1030 pre_max_area
.y
= moveresize_client
->pre_max_area
.y
;
1031 pre_max_area
.height
=
1032 moveresize_client
->pre_max_area
.height
;
1034 moveresize_client
->pre_max_area
.y
= cur_y
;
1035 moveresize_client
->pre_max_area
.height
= cur_h
;
1036 client_maximize(moveresize_client
, FALSE
, 2);
1039 else if (was_max_vert
&& !moveresize_client
->max_vert
) {
1040 /* remax vert and put the premax back */
1041 client_maximize(moveresize_client
, TRUE
, 2);
1042 moveresize_client
->pre_max_area
.y
= pre_max_area
.y
;
1043 moveresize_client
->pre_max_area
.height
= pre_max_area
.height
;
1046 dw
-= cur_w
- start_cw
;
1047 dh
-= cur_h
- start_ch
;
1049 calc_resize(FALSE
, 0, &dw
, &dh
, dir
);
1053 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
1054 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT
) ||
1055 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
))
1059 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT
) ||
1060 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP
) ||
1061 corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT
))
1069 } else if (e
->type
== KeyPress
) {
1070 KeySym sym
= obt_keyboard_keypress_to_keysym(e
);
1072 if (sym
== XK_Escape
) {
1073 moveresize_end(TRUE
);
1075 } else if (sym
== XK_Return
|| sym
== XK_KP_Enter
) {
1076 moveresize_end(FALSE
);
1078 } else if (sym
== XK_Right
|| sym
== XK_Left
||
1079 sym
== XK_Up
|| sym
== XK_Down
)
1081 if (corner
== OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD
)) {
1082 resize_with_keys(sym
, e
->xkey
.state
);
1084 } else if (corner
==
1085 OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD
))
1087 move_with_keys(sym
, e
->xkey
.state
);
1093 else if (e
->type
== obt_display_extension_sync_basep
+ XSyncAlarmNotify
)
1095 waiting_for_sync
= 0; /* we got our sync... */
1096 do_resize(); /* ...so try resize if there is more change pending */
1101 if (used
&& moveresize_client
== focus_client
)
1102 event_update_user_time();