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
);
200 /* get where the client should be */
201 frame_frame_gravity(moveresize_client
->frame
, &cur_x
, &cur_y
);
202 client_configure(moveresize_client
, OB_CORNER_TOPLEFT
, cur_x
, cur_y
,
203 moveresize_client
->area
.width
,
204 moveresize_client
->area
.height
, TRUE
, FALSE
);
205 if (config_resize_popup_show
== 2) /* == "Always" */
206 popup_coords(moveresize_client
, "%d x %d",
207 moveresize_client
->frame
->area
.x
,
208 moveresize_client
->frame
->area
.y
);
211 static void do_resize(gboolean resist
)
213 /* resist_size_* needs the frame size */
214 cur_x
+= moveresize_client
->frame
->size
.left
+
215 moveresize_client
->frame
->size
.right
;
216 cur_y
+= moveresize_client
->frame
->size
.top
+
217 moveresize_client
->frame
->size
.bottom
;
220 resist_size_windows(moveresize_client
, &cur_x
, &cur_y
, lockcorner
);
221 resist_size_monitors(moveresize_client
, &cur_x
, &cur_y
, lockcorner
);
223 cur_x
-= moveresize_client
->frame
->size
.left
+
224 moveresize_client
->frame
->size
.right
;
225 cur_y
-= moveresize_client
->frame
->size
.top
+
226 moveresize_client
->frame
->size
.bottom
;
228 client_configure(moveresize_client
, lockcorner
,
229 moveresize_client
->area
.x
, moveresize_client
->area
.y
,
230 cur_x
, cur_y
, TRUE
, FALSE
);
232 /* this would be better with a fixed width font ... XXX can do it better
233 if there are 2 text boxes */
234 if (config_resize_popup_show
== 2 || /* == "Always" */
235 (config_resize_popup_show
== 1 && /* == "Nonpixel" */
236 (moveresize_client
->size_inc
.width
> 1 ||
237 moveresize_client
->size_inc
.height
> 1))
239 popup_coords(moveresize_client
, "%d x %d",
240 moveresize_client
->logical_size
.width
,
241 moveresize_client
->logical_size
.height
);
244 void moveresize_event(XEvent
*e
)
246 g_assert(moveresize_in_progress
);
248 if (e
->type
== ButtonPress
) {
250 start_x
= e
->xbutton
.x_root
;
251 start_y
= e
->xbutton
.y_root
;
252 button
= e
->xbutton
.button
; /* this will end it now */
254 } else if (e
->type
== ButtonRelease
) {
255 if (!button
|| e
->xbutton
.button
== button
) {
256 moveresize_end(FALSE
);
258 } else if (e
->type
== MotionNotify
) {
260 cur_x
= start_cx
+ e
->xmotion
.x_root
- start_x
;
261 cur_y
= start_cy
+ e
->xmotion
.y_root
- start_y
;
264 if (corner
== prop_atoms
.net_wm_moveresize_size_topleft
) {
265 cur_x
= start_cw
- (e
->xmotion
.x_root
- start_x
);
266 cur_y
= start_ch
- (e
->xmotion
.y_root
- start_y
);
267 lockcorner
= OB_CORNER_BOTTOMRIGHT
;
268 } else if (corner
== prop_atoms
.net_wm_moveresize_size_top
) {
270 cur_y
= start_ch
- (e
->xmotion
.y_root
- start_y
);
271 lockcorner
= OB_CORNER_BOTTOMRIGHT
;
272 } else if (corner
== prop_atoms
.net_wm_moveresize_size_topright
) {
273 cur_x
= start_cw
+ (e
->xmotion
.x_root
- start_x
);
274 cur_y
= start_ch
- (e
->xmotion
.y_root
- start_y
);
275 lockcorner
= OB_CORNER_BOTTOMLEFT
;
276 } else if (corner
== prop_atoms
.net_wm_moveresize_size_right
) {
277 cur_x
= start_cw
+ (e
->xmotion
.x_root
- start_x
);
279 lockcorner
= OB_CORNER_BOTTOMLEFT
;
281 prop_atoms
.net_wm_moveresize_size_bottomright
) {
282 cur_x
= start_cw
+ (e
->xmotion
.x_root
- start_x
);
283 cur_y
= start_ch
+ (e
->xmotion
.y_root
- start_y
);
284 lockcorner
= OB_CORNER_TOPLEFT
;
285 } else if (corner
== prop_atoms
.net_wm_moveresize_size_bottom
) {
287 cur_y
= start_ch
+ (e
->xmotion
.y_root
- start_y
);
288 lockcorner
= OB_CORNER_TOPLEFT
;
290 prop_atoms
.net_wm_moveresize_size_bottomleft
) {
291 cur_x
= start_cw
- (e
->xmotion
.x_root
- start_x
);
292 cur_y
= start_ch
+ (e
->xmotion
.y_root
- start_y
);
293 lockcorner
= OB_CORNER_TOPRIGHT
;
294 } else if (corner
== prop_atoms
.net_wm_moveresize_size_left
) {
295 cur_x
= start_cw
- (e
->xmotion
.x_root
- start_x
);
297 lockcorner
= OB_CORNER_TOPRIGHT
;
298 } else if (corner
== prop_atoms
.net_wm_moveresize_size_keyboard
) {
299 cur_x
= start_cw
+ (e
->xmotion
.x_root
- start_x
);
300 cur_y
= start_ch
+ (e
->xmotion
.y_root
- start_y
);
301 lockcorner
= OB_CORNER_TOPLEFT
;
303 g_assert_not_reached();
307 } else if (e
->type
== KeyPress
) {
308 if (e
->xkey
.keycode
== ob_keycode(OB_KEY_ESCAPE
))
309 moveresize_end(TRUE
);
310 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RETURN
))
311 moveresize_end(FALSE
);
313 if (corner
== prop_atoms
.net_wm_moveresize_size_keyboard
) {
314 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
316 if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RIGHT
))
317 dx
= MAX(4, moveresize_client
->size_inc
.width
);
318 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_LEFT
))
319 dx
= -MAX(4, moveresize_client
->size_inc
.width
);
320 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_DOWN
))
321 dy
= MAX(4, moveresize_client
->size_inc
.height
);
322 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_UP
))
323 dy
= -MAX(4, moveresize_client
->size_inc
.height
);
329 XWarpPointer(ob_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
330 /* steal the motion events this causes */
331 XSync(ob_display
, FALSE
);
334 while (XCheckTypedEvent(ob_display
, MotionNotify
, &ce
));
339 /* because the cursor moves even though the window does
340 not nessesarily (resistance), this adjusts where the curor
341 thinks it started so that it keeps up with where the window
343 start_x
+= dx
- (cur_x
- ox
);
344 start_y
+= dy
- (cur_y
- oy
);
345 } else if (corner
== prop_atoms
.net_wm_moveresize_move_keyboard
) {
346 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
347 gint opx
, px
, opy
, py
;
349 if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RIGHT
))
351 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_LEFT
))
353 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_DOWN
))
355 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_UP
))
362 screen_pointer_pos(&opx
, &opy
);
363 XWarpPointer(ob_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
364 /* steal the motion events this causes */
365 XSync(ob_display
, FALSE
);
368 while (XCheckTypedEvent(ob_display
, MotionNotify
, &ce
));
370 screen_pointer_pos(&px
, &py
);
374 /* because the cursor moves even though the window does
375 not nessesarily (resistance), this adjusts where the curor
376 thinks it started so that it keeps up with where the window
378 start_x
+= (px
- opx
) - (cur_x
- ox
);
379 start_y
+= (py
- opy
) - (cur_y
- oy
);