1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 moveresize.c for the Openbox window manager
4 Copyright (c) 2004 Mikael Magnusson
5 Copyright (c) 2003 Ben 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"
31 #include "render/render.h"
32 #include "render/theme.h"
37 gboolean moveresize_in_progress
= FALSE
;
38 ObClient
*moveresize_client
= NULL
;
40 static gboolean moving
= FALSE
; /* TRUE - moving, FALSE - resizing */
42 static gint start_x
, start_y
, start_cx
, start_cy
, start_cw
, start_ch
;
43 static gint cur_x
, cur_y
;
45 static guint32 corner
;
46 static ObCorner lockcorner
;
48 static ObPopup
*popup
= NULL
;
50 static void client_dest(ObClient
*client
, gpointer data
)
52 if (moveresize_client
== client
)
56 void moveresize_startup(gboolean reconfig
)
58 popup
= popup_new(FALSE
);
61 client_add_destructor(client_dest
, NULL
);
64 void moveresize_shutdown(gboolean reconfig
)
67 if (moveresize_in_progress
)
68 moveresize_end(FALSE
);
69 client_remove_destructor(client_dest
);
76 static void popup_coords(ObClient
*c
, gchar
*format
, gint a
, gint b
)
80 text
= g_strdup_printf(format
, a
, b
);
81 if (config_resize_popup_pos
== 1) /* == "Top" */
82 popup_position(popup
, SouthGravity
,
84 + c
->frame
->area
.width
/2,
86 else /* == "Center" */
87 popup_position(popup
, CenterGravity
,
88 c
->frame
->area
.x
+ c
->frame
->size
.left
+
90 c
->frame
->area
.y
+ c
->frame
->size
.top
+
92 popup_show(popup
, text
);
96 void moveresize_start(ObClient
*c
, gint x
, gint y
, guint b
, guint32 cnr
)
100 moving
= (cnr
== prop_atoms
.net_wm_moveresize_move
||
101 cnr
== prop_atoms
.net_wm_moveresize_move_keyboard
);
103 if (moveresize_in_progress
|| !c
->frame
->visible
||
105 (c
->functions
& OB_CLIENT_FUNC_MOVE
) :
106 (c
->functions
& OB_CLIENT_FUNC_RESIZE
)))
109 moveresize_client
= c
;
110 start_cx
= c
->frame
->area
.x
;
111 start_cy
= c
->frame
->area
.y
;
112 /* these adjustments for the size_inc make resizing a terminal more
113 friendly. you essentially start the resize in the middle of the
114 increment instead of at 0, so you have to move half an increment
115 either way instead of a full increment one and 1 px the other. and this
116 is one large mother fucking comment. */
117 start_cw
= c
->area
.width
+ c
->size_inc
.width
/ 2;
118 start_ch
= c
->area
.height
+ c
->size_inc
.height
/ 2;
125 have to change start_cx and start_cy if going to do this..
126 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
127 corner == prop_atoms.net_wm_moveresize_size_keyboard)
128 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
129 c->area.width / 2, c->area.height / 2);
140 moveresize_in_progress
= TRUE
;
142 if (corner
== prop_atoms
.net_wm_moveresize_size_topleft
)
143 cur
= OB_CURSOR_NORTHWEST
;
144 else if (corner
== prop_atoms
.net_wm_moveresize_size_top
)
145 cur
= OB_CURSOR_NORTH
;
146 else if (corner
== prop_atoms
.net_wm_moveresize_size_topright
)
147 cur
= OB_CURSOR_NORTHEAST
;
148 else if (corner
== prop_atoms
.net_wm_moveresize_size_right
)
149 cur
= OB_CURSOR_EAST
;
150 else if (corner
== prop_atoms
.net_wm_moveresize_size_bottomright
)
151 cur
= OB_CURSOR_SOUTHEAST
;
152 else if (corner
== prop_atoms
.net_wm_moveresize_size_bottom
)
153 cur
= OB_CURSOR_SOUTH
;
154 else if (corner
== prop_atoms
.net_wm_moveresize_size_bottomleft
)
155 cur
= OB_CURSOR_SOUTHWEST
;
156 else if (corner
== prop_atoms
.net_wm_moveresize_size_left
)
157 cur
= OB_CURSOR_WEST
;
158 else if (corner
== prop_atoms
.net_wm_moveresize_size_keyboard
)
159 cur
= OB_CURSOR_SOUTHEAST
;
160 else if (corner
== prop_atoms
.net_wm_moveresize_move
)
161 cur
= OB_CURSOR_MOVE
;
162 else if (corner
== prop_atoms
.net_wm_moveresize_move_keyboard
)
163 cur
= OB_CURSOR_MOVE
;
165 g_assert_not_reached();
167 grab_pointer(TRUE
, cur
);
171 void moveresize_end(gboolean cancel
)
173 grab_keyboard(FALSE
);
174 grab_pointer(FALSE
, OB_CURSOR_NONE
);
179 client_move(moveresize_client
,
180 (cancel
? start_cx
: cur_x
),
181 (cancel
? start_cy
: cur_y
));
183 client_configure(moveresize_client
, lockcorner
,
184 moveresize_client
->area
.x
,
185 moveresize_client
->area
.y
,
186 (cancel
? start_cw
: cur_x
),
187 (cancel
? start_ch
: cur_y
), TRUE
, TRUE
);
190 moveresize_in_progress
= FALSE
;
191 moveresize_client
= NULL
;
194 static void do_move(gboolean resist
)
197 resist_move_windows(moveresize_client
, &cur_x
, &cur_y
);
198 resist_move_monitors(moveresize_client
, &cur_x
, &cur_y
);
201 /* get where the client should be */
202 frame_frame_gravity(moveresize_client
->frame
, &cur_x
, &cur_y
);
203 client_configure(moveresize_client
, OB_CORNER_TOPLEFT
, cur_x
, cur_y
,
204 moveresize_client
->area
.width
,
205 moveresize_client
->area
.height
, TRUE
, FALSE
);
206 if (config_resize_popup_show
== 2) /* == "Always" */
207 popup_coords(moveresize_client
, "%d x %d",
208 moveresize_client
->frame
->area
.x
,
209 moveresize_client
->frame
->area
.y
);
212 static void do_resize(gboolean resist
)
214 /* resist_size_* needs the frame size */
215 cur_x
+= moveresize_client
->frame
->size
.left
+
216 moveresize_client
->frame
->size
.right
;
217 cur_y
+= moveresize_client
->frame
->size
.top
+
218 moveresize_client
->frame
->size
.bottom
;
221 resist_size_windows(moveresize_client
, &cur_x
, &cur_y
, lockcorner
);
222 resist_size_monitors(moveresize_client
, &cur_x
, &cur_y
, lockcorner
);
225 cur_x
-= moveresize_client
->frame
->size
.left
+
226 moveresize_client
->frame
->size
.right
;
227 cur_y
-= moveresize_client
->frame
->size
.top
+
228 moveresize_client
->frame
->size
.bottom
;
230 client_configure(moveresize_client
, lockcorner
,
231 moveresize_client
->area
.x
, moveresize_client
->area
.y
,
232 cur_x
, cur_y
, TRUE
, FALSE
);
234 /* this would be better with a fixed width font ... XXX can do it better
235 if there are 2 text boxes */
236 if (config_resize_popup_show
== 2 || /* == "Always" */
237 (config_resize_popup_show
== 1 && /* == "Nonpixel" */
238 (moveresize_client
->size_inc
.width
> 1 ||
239 moveresize_client
->size_inc
.height
> 1))
241 popup_coords(moveresize_client
, "%d x %d",
242 moveresize_client
->logical_size
.width
,
243 moveresize_client
->logical_size
.height
);
246 void moveresize_event(XEvent
*e
)
248 g_assert(moveresize_in_progress
);
250 if (e
->type
== ButtonPress
) {
252 start_x
= e
->xbutton
.x_root
;
253 start_y
= e
->xbutton
.y_root
;
254 button
= e
->xbutton
.button
; /* this will end it now */
256 } else if (e
->type
== ButtonRelease
) {
257 if (!button
|| e
->xbutton
.button
== button
) {
258 moveresize_end(FALSE
);
260 } else if (e
->type
== MotionNotify
) {
262 cur_x
= start_cx
+ e
->xmotion
.x_root
- start_x
;
263 cur_y
= start_cy
+ e
->xmotion
.y_root
- start_y
;
266 if (corner
== prop_atoms
.net_wm_moveresize_size_topleft
) {
267 cur_x
= start_cw
- (e
->xmotion
.x_root
- start_x
);
268 cur_y
= start_ch
- (e
->xmotion
.y_root
- start_y
);
269 lockcorner
= OB_CORNER_BOTTOMRIGHT
;
270 } else if (corner
== prop_atoms
.net_wm_moveresize_size_top
) {
272 cur_y
= start_ch
- (e
->xmotion
.y_root
- start_y
);
273 lockcorner
= OB_CORNER_BOTTOMRIGHT
;
274 } else if (corner
== prop_atoms
.net_wm_moveresize_size_topright
) {
275 cur_x
= start_cw
+ (e
->xmotion
.x_root
- start_x
);
276 cur_y
= start_ch
- (e
->xmotion
.y_root
- start_y
);
277 lockcorner
= OB_CORNER_BOTTOMLEFT
;
278 } else if (corner
== prop_atoms
.net_wm_moveresize_size_right
) {
279 cur_x
= start_cw
+ (e
->xmotion
.x_root
- start_x
);
281 lockcorner
= OB_CORNER_BOTTOMLEFT
;
283 prop_atoms
.net_wm_moveresize_size_bottomright
) {
284 cur_x
= start_cw
+ (e
->xmotion
.x_root
- start_x
);
285 cur_y
= start_ch
+ (e
->xmotion
.y_root
- start_y
);
286 lockcorner
= OB_CORNER_TOPLEFT
;
287 } else if (corner
== prop_atoms
.net_wm_moveresize_size_bottom
) {
289 cur_y
= start_ch
+ (e
->xmotion
.y_root
- start_y
);
290 lockcorner
= OB_CORNER_TOPLEFT
;
292 prop_atoms
.net_wm_moveresize_size_bottomleft
) {
293 cur_x
= start_cw
- (e
->xmotion
.x_root
- start_x
);
294 cur_y
= start_ch
+ (e
->xmotion
.y_root
- start_y
);
295 lockcorner
= OB_CORNER_TOPRIGHT
;
296 } else if (corner
== prop_atoms
.net_wm_moveresize_size_left
) {
297 cur_x
= start_cw
- (e
->xmotion
.x_root
- start_x
);
299 lockcorner
= OB_CORNER_TOPRIGHT
;
300 } else if (corner
== prop_atoms
.net_wm_moveresize_size_keyboard
) {
301 cur_x
= start_cw
+ (e
->xmotion
.x_root
- start_x
);
302 cur_y
= start_ch
+ (e
->xmotion
.y_root
- start_y
);
303 lockcorner
= OB_CORNER_TOPLEFT
;
305 g_assert_not_reached();
309 } else if (e
->type
== KeyPress
) {
310 if (e
->xkey
.keycode
== ob_keycode(OB_KEY_ESCAPE
))
311 moveresize_end(TRUE
);
312 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RETURN
))
313 moveresize_end(FALSE
);
315 if (corner
== prop_atoms
.net_wm_moveresize_size_keyboard
) {
316 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
318 if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RIGHT
))
319 dx
= MAX(4, moveresize_client
->size_inc
.width
);
320 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_LEFT
))
321 dx
= -MAX(4, moveresize_client
->size_inc
.width
);
322 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_DOWN
))
323 dy
= MAX(4, moveresize_client
->size_inc
.height
);
324 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_UP
))
325 dy
= -MAX(4, moveresize_client
->size_inc
.height
);
331 XWarpPointer(ob_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
332 /* steal the motion events this causes */
333 XSync(ob_display
, FALSE
);
336 while (XCheckTypedEvent(ob_display
, MotionNotify
, &ce
));
341 /* because the cursor moves even though the window does
342 not nessesarily (resistance), this adjusts where the curor
343 thinks it started so that it keeps up with where the window
345 start_x
+= dx
- (cur_x
- ox
);
346 start_y
+= dy
- (cur_y
- oy
);
347 } else if (corner
== prop_atoms
.net_wm_moveresize_move_keyboard
) {
348 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
349 gint opx
, px
, opy
, py
;
351 if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RIGHT
))
353 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_LEFT
))
355 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_DOWN
))
357 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_UP
))
364 screen_pointer_pos(&opx
, &opy
);
365 XWarpPointer(ob_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
366 /* steal the motion events this causes */
367 XSync(ob_display
, FALSE
);
370 while (XCheckTypedEvent(ob_display
, MotionNotify
, &ce
));
372 screen_pointer_pos(&px
, &py
);
376 /* because the cursor moves even though the window does
377 not nessesarily (resistance), this adjusts where the curor
378 thinks it started so that it keeps up with where the window
380 start_x
+= (px
- opx
) - (cur_x
- ox
);
381 start_y
+= (py
- opy
) - (cur_y
- oy
);