1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 moveresize.c for the Openbox window manager
4 Copyright (c) 2003 Ben Jansens
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 See the COPYING file for a copy of the GNU General Public License.
20 #include "framerender.h"
28 #include "moveresize.h"
30 #include "render/render.h"
31 #include "render/theme.h"
36 gboolean moveresize_in_progress
= FALSE
;
37 ObClient
*moveresize_client
= NULL
;
39 static gboolean moving
= FALSE
; /* TRUE - moving, FALSE - resizing */
41 static gint start_x
, start_y
, start_cx
, start_cy
, start_cw
, start_ch
;
42 static gint cur_x
, cur_y
;
44 static guint32 corner
;
45 static ObCorner lockcorner
;
47 static ObPopup
*popup
= NULL
;
49 static void client_dest(ObClient
*client
, gpointer data
)
51 if (moveresize_client
== client
)
55 void moveresize_startup(gboolean reconfig
)
57 popup
= popup_new(FALSE
);
60 client_add_destructor(client_dest
, NULL
);
63 void moveresize_shutdown(gboolean reconfig
)
66 if (moveresize_in_progress
)
67 moveresize_end(FALSE
);
68 client_remove_destructor(client_dest
);
75 static void popup_coords(ObClient
*c
, gchar
*format
, gint a
, gint b
)
79 text
= g_strdup_printf(format
, a
, b
);
80 popup_position(popup
, CenterGravity
,
81 c
->frame
->area
.x
+ c
->frame
->size
.left
+
83 c
->frame
->area
.y
+ c
->frame
->size
.top
+
85 popup_show(popup
, text
);
89 void moveresize_start(ObClient
*c
, gint x
, gint y
, guint b
, guint32 cnr
)
93 moving
= (cnr
== prop_atoms
.net_wm_moveresize_move
||
94 cnr
== prop_atoms
.net_wm_moveresize_move_keyboard
);
96 if (moveresize_in_progress
|| !c
->frame
->visible
||
98 (c
->functions
& OB_CLIENT_FUNC_MOVE
) :
99 (c
->functions
& OB_CLIENT_FUNC_RESIZE
)))
102 moveresize_client
= c
;
103 start_cx
= c
->frame
->area
.x
;
104 start_cy
= c
->frame
->area
.y
;
105 /* these adjustments for the size_inc make resizing a terminal more
106 friendly. you essentially start the resize in the middle of the
107 increment instead of at 0, so you have to move half an increment
108 either way instead of a full increment one and 1 px the other. and this
109 is one large mother fucking comment. */
110 start_cw
= c
->area
.width
+ c
->size_inc
.width
/ 2;
111 start_ch
= c
->area
.height
+ c
->size_inc
.height
/ 2;
118 have to change start_cx and start_cy if going to do this..
119 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
120 corner == prop_atoms.net_wm_moveresize_size_keyboard)
121 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
122 c->area.width / 2, c->area.height / 2);
133 moveresize_in_progress
= TRUE
;
135 if (corner
== prop_atoms
.net_wm_moveresize_size_topleft
)
136 cur
= OB_CURSOR_NORTHWEST
;
137 else if (corner
== prop_atoms
.net_wm_moveresize_size_top
)
138 cur
= OB_CURSOR_NORTH
;
139 else if (corner
== prop_atoms
.net_wm_moveresize_size_topright
)
140 cur
= OB_CURSOR_NORTHEAST
;
141 else if (corner
== prop_atoms
.net_wm_moveresize_size_right
)
142 cur
= OB_CURSOR_EAST
;
143 else if (corner
== prop_atoms
.net_wm_moveresize_size_bottomright
)
144 cur
= OB_CURSOR_SOUTHEAST
;
145 else if (corner
== prop_atoms
.net_wm_moveresize_size_bottom
)
146 cur
= OB_CURSOR_SOUTH
;
147 else if (corner
== prop_atoms
.net_wm_moveresize_size_bottomleft
)
148 cur
= OB_CURSOR_SOUTHWEST
;
149 else if (corner
== prop_atoms
.net_wm_moveresize_size_left
)
150 cur
= OB_CURSOR_WEST
;
151 else if (corner
== prop_atoms
.net_wm_moveresize_size_keyboard
)
152 cur
= OB_CURSOR_SOUTHEAST
;
153 else if (corner
== prop_atoms
.net_wm_moveresize_move
)
154 cur
= OB_CURSOR_MOVE
;
155 else if (corner
== prop_atoms
.net_wm_moveresize_move_keyboard
)
156 cur
= OB_CURSOR_MOVE
;
158 g_assert_not_reached();
160 grab_pointer(TRUE
, cur
);
164 void moveresize_end(gboolean cancel
)
166 grab_keyboard(FALSE
);
167 grab_pointer(FALSE
, OB_CURSOR_NONE
);
172 client_move(moveresize_client
,
173 (cancel
? start_cx
: cur_x
),
174 (cancel
? start_cy
: cur_y
));
176 client_configure(moveresize_client
, lockcorner
,
177 moveresize_client
->area
.x
,
178 moveresize_client
->area
.y
,
179 (cancel
? start_cw
: cur_x
),
180 (cancel
? start_ch
: cur_y
), TRUE
, TRUE
);
183 moveresize_in_progress
= FALSE
;
184 moveresize_client
= NULL
;
187 static void do_move(gboolean resist
)
190 resist_move_windows(moveresize_client
, &cur_x
, &cur_y
);
191 resist_move_monitors(moveresize_client
, &cur_x
, &cur_y
);
193 /* get where the client should be */
194 frame_frame_gravity(moveresize_client
->frame
, &cur_x
, &cur_y
);
195 client_configure(moveresize_client
, OB_CORNER_TOPLEFT
, cur_x
, cur_y
,
196 moveresize_client
->area
.width
,
197 moveresize_client
->area
.height
, TRUE
, FALSE
);
198 if (config_resize_popup_show
== 2) /* == "Always" */
199 popup_coords(moveresize_client
, "%d x %d",
200 moveresize_client
->frame
->area
.x
,
201 moveresize_client
->frame
->area
.y
);
204 static void do_resize(gboolean resist
)
206 /* resist_size_* needs the frame size */
207 cur_x
+= moveresize_client
->frame
->size
.left
+
208 moveresize_client
->frame
->size
.right
;
209 cur_y
+= moveresize_client
->frame
->size
.top
+
210 moveresize_client
->frame
->size
.bottom
;
213 resist_size_windows(moveresize_client
, &cur_x
, &cur_y
, lockcorner
);
214 resist_size_monitors(moveresize_client
, &cur_x
, &cur_y
, lockcorner
);
216 cur_x
-= moveresize_client
->frame
->size
.left
+
217 moveresize_client
->frame
->size
.right
;
218 cur_y
-= moveresize_client
->frame
->size
.top
+
219 moveresize_client
->frame
->size
.bottom
;
221 client_configure(moveresize_client
, lockcorner
,
222 moveresize_client
->area
.x
, moveresize_client
->area
.y
,
223 cur_x
, cur_y
, TRUE
, FALSE
);
225 /* this would be better with a fixed width font ... XXX can do it better
226 if there are 2 text boxes */
227 if (config_resize_popup_show
== 2 || /* == "Always" */
228 (config_resize_popup_show
== 1 && /* == "Nonpixel" */
229 (moveresize_client
->size_inc
.width
> 1 ||
230 moveresize_client
->size_inc
.height
> 1))
232 popup_coords(moveresize_client
, "%d x %d",
233 moveresize_client
->logical_size
.width
,
234 moveresize_client
->logical_size
.height
);
237 void moveresize_event(XEvent
*e
)
239 g_assert(moveresize_in_progress
);
241 if (e
->type
== ButtonPress
) {
243 start_x
= e
->xbutton
.x_root
;
244 start_y
= e
->xbutton
.y_root
;
245 button
= e
->xbutton
.button
; /* this will end it now */
247 } else if (e
->type
== ButtonRelease
) {
248 if (!button
|| e
->xbutton
.button
== button
) {
249 moveresize_end(FALSE
);
251 } else if (e
->type
== MotionNotify
) {
253 cur_x
= start_cx
+ e
->xmotion
.x_root
- start_x
;
254 cur_y
= start_cy
+ e
->xmotion
.y_root
- start_y
;
257 if (corner
== prop_atoms
.net_wm_moveresize_size_topleft
) {
258 cur_x
= start_cw
- (e
->xmotion
.x_root
- start_x
);
259 cur_y
= start_ch
- (e
->xmotion
.y_root
- start_y
);
260 lockcorner
= OB_CORNER_BOTTOMRIGHT
;
261 } else if (corner
== prop_atoms
.net_wm_moveresize_size_top
) {
263 cur_y
= start_ch
- (e
->xmotion
.y_root
- start_y
);
264 lockcorner
= OB_CORNER_BOTTOMRIGHT
;
265 } else if (corner
== prop_atoms
.net_wm_moveresize_size_topright
) {
266 cur_x
= start_cw
+ (e
->xmotion
.x_root
- start_x
);
267 cur_y
= start_ch
- (e
->xmotion
.y_root
- start_y
);
268 lockcorner
= OB_CORNER_BOTTOMLEFT
;
269 } else if (corner
== prop_atoms
.net_wm_moveresize_size_right
) {
270 cur_x
= start_cw
+ (e
->xmotion
.x_root
- start_x
);
272 lockcorner
= OB_CORNER_BOTTOMLEFT
;
274 prop_atoms
.net_wm_moveresize_size_bottomright
) {
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_TOPLEFT
;
278 } else if (corner
== prop_atoms
.net_wm_moveresize_size_bottom
) {
280 cur_y
= start_ch
+ (e
->xmotion
.y_root
- start_y
);
281 lockcorner
= OB_CORNER_TOPLEFT
;
283 prop_atoms
.net_wm_moveresize_size_bottomleft
) {
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_TOPRIGHT
;
287 } else if (corner
== prop_atoms
.net_wm_moveresize_size_left
) {
288 cur_x
= start_cw
- (e
->xmotion
.x_root
- start_x
);
290 lockcorner
= OB_CORNER_TOPRIGHT
;
291 } else if (corner
== prop_atoms
.net_wm_moveresize_size_keyboard
) {
292 cur_x
= start_cw
+ (e
->xmotion
.x_root
- start_x
);
293 cur_y
= start_ch
+ (e
->xmotion
.y_root
- start_y
);
294 lockcorner
= OB_CORNER_TOPLEFT
;
296 g_assert_not_reached();
300 } else if (e
->type
== KeyPress
) {
301 if (e
->xkey
.keycode
== ob_keycode(OB_KEY_ESCAPE
))
302 moveresize_end(TRUE
);
303 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RETURN
))
304 moveresize_end(FALSE
);
306 if (corner
== prop_atoms
.net_wm_moveresize_size_keyboard
) {
307 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
309 if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RIGHT
))
310 dx
= MAX(4, moveresize_client
->size_inc
.width
);
311 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_LEFT
))
312 dx
= -MAX(4, moveresize_client
->size_inc
.width
);
313 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_DOWN
))
314 dy
= MAX(4, moveresize_client
->size_inc
.height
);
315 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_UP
))
316 dy
= -MAX(4, moveresize_client
->size_inc
.height
);
322 XWarpPointer(ob_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
323 /* steal the motion events this causes */
324 XSync(ob_display
, FALSE
);
327 while (XCheckTypedEvent(ob_display
, MotionNotify
, &ce
));
332 /* because the cursor moves even though the window does
333 not nessesarily (resistance), this adjusts where the curor
334 thinks it started so that it keeps up with where the window
336 start_x
+= dx
- (cur_x
- ox
);
337 start_y
+= dy
- (cur_y
- oy
);
338 } else if (corner
== prop_atoms
.net_wm_moveresize_move_keyboard
) {
339 gint dx
= 0, dy
= 0, ox
= cur_x
, oy
= cur_y
;
340 gint opx
, px
, opy
, py
;
342 if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RIGHT
))
344 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_LEFT
))
346 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_DOWN
))
348 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_UP
))
355 screen_pointer_pos(&opx
, &opy
);
356 XWarpPointer(ob_display
, None
, None
, 0, 0, 0, 0, dx
, dy
);
357 /* steal the motion events this causes */
358 XSync(ob_display
, FALSE
);
361 while (XCheckTypedEvent(ob_display
, MotionNotify
, &ce
));
363 screen_pointer_pos(&px
, &py
);
367 /* because the cursor moves even though the window does
368 not nessesarily (resistance), this adjusts where the curor
369 thinks it started so that it keeps up with where the window
371 start_x
+= (px
- opx
) - (cur_x
- ox
);
372 start_y
+= (py
- opy
) - (cur_y
- oy
);