]> Dogcows Code - chaz/openbox/blob - openbox/moveresize.c
ba10af4b3adb4cd2faa8a088d0b5fb9546a90c6f
[chaz/openbox] / openbox / moveresize.c
1 /* -*- indent-tabs-mode: t; tab-width: 4; c-basic-offset: 4; -*-
2
3 moveresize.c for the Openbox window manager
4 Copyright (c) 2003 Ben Jansens
5
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.
10
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.
15
16 See the COPYING file for a copy of the GNU General Public License.
17 */
18
19 #include "grab.h"
20 #include "framerender.h"
21 #include "screen.h"
22 #include "prop.h"
23 #include "client.h"
24 #include "frame.h"
25 #include "openbox.h"
26 #include "resist.h"
27 #include "popup.h"
28 #include "moveresize.h"
29 #include "config.h"
30 #include "render/render.h"
31 #include "render/theme.h"
32
33 #include <X11/Xlib.h>
34 #include <glib.h>
35
36 gboolean moveresize_in_progress = FALSE;
37 ObClient *moveresize_client = NULL;
38
39 static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */
40
41 static int start_x, start_y, start_cx, start_cy, start_cw, start_ch;
42 static int cur_x, cur_y;
43 static guint button;
44 static guint32 corner;
45 static ObCorner lockcorner;
46
47 static ObPopup *popup = NULL;
48
49 static void client_dest(gpointer client)
50 {
51 if (moveresize_client == client)
52 moveresize_end(TRUE);
53 }
54
55 void moveresize_startup(gboolean reconfig)
56 {
57 popup = popup_new(FALSE);
58
59 if (!reconfig)
60 client_add_destructor(client_dest);
61 }
62
63 void moveresize_shutdown(gboolean reconfig)
64 {
65 if (!reconfig) {
66 if (moveresize_in_progress)
67 moveresize_end(FALSE);
68 client_remove_destructor(client_dest);
69 }
70
71 popup_free(popup);
72 popup = NULL;
73 }
74
75 static void popup_coords(ObClient *c, char *format, int a, int b)
76 {
77 char *text;
78
79 text = g_strdup_printf(format, a, b);
80 popup_position(popup, CenterGravity,
81 c->frame->area.x + c->frame->size.left +
82 c->area.width / 2,
83 c->frame->area.y + c->frame->size.top +
84 c->area.height / 2);
85 popup_show(popup, text);
86 g_free(text);
87 }
88
89 void moveresize_start(ObClient *c, int x, int y, guint b, guint32 cnr)
90 {
91 ObCursor cur;
92
93 if (moveresize_in_progress || !c->frame->visible)
94 return;
95
96 moveresize_client = c;
97 start_cx = c->frame->area.x;
98 start_cy = c->frame->area.y;
99 /* these adjustments for the size_inc make resizing a terminal more
100 friendly. you essentially start the resize in the middle of the
101 increment instead of at 0, so you have to move half an increment
102 either way instead of a full increment one and 1 px the other. and this
103 is one large mother fucking comment. */
104 start_cw = c->area.width + c->size_inc.width / 2;
105 start_ch = c->area.height + c->size_inc.height / 2;
106 start_x = x;
107 start_y = y;
108 corner = cnr;
109 button = b;
110
111 /*
112 have to change start_cx and start_cy if going to do this..
113 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
114 corner == prop_atoms.net_wm_moveresize_size_keyboard)
115 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
116 c->area.width / 2, c->area.height / 2);
117 */
118
119 if (corner == prop_atoms.net_wm_moveresize_move ||
120 corner == prop_atoms.net_wm_moveresize_move_keyboard) {
121 cur_x = start_cx;
122 cur_y = start_cy;
123 moving = TRUE;
124 } else {
125 cur_x = start_cw;
126 cur_y = start_ch;
127 moving = FALSE;
128 }
129
130 moveresize_in_progress = TRUE;
131
132 if (corner == prop_atoms.net_wm_moveresize_size_topleft)
133 cur = OB_CURSOR_NORTHWEST;
134 else if (corner == prop_atoms.net_wm_moveresize_size_top)
135 cur = OB_CURSOR_NORTH;
136 else if (corner == prop_atoms.net_wm_moveresize_size_topright)
137 cur = OB_CURSOR_NORTHEAST;
138 else if (corner == prop_atoms.net_wm_moveresize_size_right)
139 cur = OB_CURSOR_EAST;
140 else if (corner == prop_atoms.net_wm_moveresize_size_bottomright)
141 cur = OB_CURSOR_SOUTHEAST;
142 else if (corner == prop_atoms.net_wm_moveresize_size_bottom)
143 cur = OB_CURSOR_SOUTH;
144 else if (corner == prop_atoms.net_wm_moveresize_size_bottomleft)
145 cur = OB_CURSOR_SOUTHWEST;
146 else if (corner == prop_atoms.net_wm_moveresize_size_left)
147 cur = OB_CURSOR_WEST;
148 else if (corner == prop_atoms.net_wm_moveresize_size_keyboard)
149 cur = OB_CURSOR_SOUTHEAST;
150 else if (corner == prop_atoms.net_wm_moveresize_move)
151 cur = OB_CURSOR_MOVE;
152 else if (corner == prop_atoms.net_wm_moveresize_move_keyboard)
153 cur = OB_CURSOR_MOVE;
154 else
155 g_assert_not_reached();
156
157 grab_pointer(TRUE, cur);
158 grab_keyboard(TRUE);
159 }
160
161 void moveresize_end(gboolean cancel)
162 {
163 grab_keyboard(FALSE);
164 grab_pointer(FALSE, OB_CURSOR_NONE);
165
166 popup_hide(popup);
167
168 if (moving) {
169 client_move(moveresize_client,
170 (cancel ? start_cx : cur_x),
171 (cancel ? start_cy : cur_y));
172 } else {
173 client_configure(moveresize_client, lockcorner,
174 moveresize_client->area.x,
175 moveresize_client->area.y,
176 (cancel ? start_cw : cur_x),
177 (cancel ? start_ch : cur_y), TRUE, TRUE);
178 }
179
180 moveresize_in_progress = FALSE;
181 moveresize_client = NULL;
182 }
183
184 static void do_move(gboolean resist)
185 {
186 if (resist)
187 resist_move_windows(moveresize_client, &cur_x, &cur_y);
188 resist_move_monitors(moveresize_client, &cur_x, &cur_y);
189
190 /* get where the client should be */
191 frame_frame_gravity(moveresize_client->frame, &cur_x, &cur_y);
192 client_configure(moveresize_client, OB_CORNER_TOPLEFT, cur_x, cur_y,
193 moveresize_client->area.width,
194 moveresize_client->area.height, TRUE, FALSE);
195 }
196
197 static void do_resize(gboolean resist)
198 {
199 /* resist_size_* needs the frame size */
200 cur_x += moveresize_client->frame->size.left +
201 moveresize_client->frame->size.right;
202 cur_y += moveresize_client->frame->size.top +
203 moveresize_client->frame->size.bottom;
204
205 if (resist)
206 resist_size_windows(moveresize_client, &cur_x, &cur_y, lockcorner);
207 resist_size_monitors(moveresize_client, &cur_x, &cur_y, lockcorner);
208
209 cur_x -= moveresize_client->frame->size.left +
210 moveresize_client->frame->size.right;
211 cur_y -= moveresize_client->frame->size.top +
212 moveresize_client->frame->size.bottom;
213
214 client_configure(moveresize_client, lockcorner,
215 moveresize_client->area.x, moveresize_client->area.y,
216 cur_x, cur_y, TRUE, FALSE);
217
218 /* this would be better with a fixed width font ... XXX can do it better
219 if there are 2 text boxes */
220 if (moveresize_client->size_inc.width > 1 ||
221 moveresize_client->size_inc.height > 1)
222 popup_coords(moveresize_client, "%d x %d",
223 moveresize_client->logical_size.width,
224 moveresize_client->logical_size.height);
225 }
226
227 void moveresize_event(XEvent *e)
228 {
229 g_assert(moveresize_in_progress);
230
231 if (e->type == ButtonPress) {
232 if (!button) {
233 start_x = e->xbutton.x_root;
234 start_y = e->xbutton.y_root;
235 button = e->xbutton.button; /* this will end it now */
236 }
237 } else if (e->type == ButtonRelease) {
238 if (!button || e->xbutton.button == button) {
239 moveresize_end(FALSE);
240 }
241 } else if (e->type == MotionNotify) {
242 if (moving) {
243 cur_x = start_cx + e->xmotion.x_root - start_x;
244 cur_y = start_cy + e->xmotion.y_root - start_y;
245 do_move(TRUE);
246 } else {
247 if (corner == prop_atoms.net_wm_moveresize_size_topleft) {
248 cur_x = start_cw - (e->xmotion.x_root - start_x);
249 cur_y = start_ch - (e->xmotion.y_root - start_y);
250 lockcorner = OB_CORNER_BOTTOMRIGHT;
251 } else if (corner == prop_atoms.net_wm_moveresize_size_top) {
252 cur_x = start_cw;
253 cur_y = start_ch - (e->xmotion.y_root - start_y);
254 lockcorner = OB_CORNER_BOTTOMRIGHT;
255 } else if (corner == prop_atoms.net_wm_moveresize_size_topright) {
256 cur_x = start_cw + (e->xmotion.x_root - start_x);
257 cur_y = start_ch - (e->xmotion.y_root - start_y);
258 lockcorner = OB_CORNER_BOTTOMLEFT;
259 } else if (corner == prop_atoms.net_wm_moveresize_size_right) {
260 cur_x = start_cw + (e->xmotion.x_root - start_x);
261 cur_y = start_ch;
262 lockcorner = OB_CORNER_BOTTOMLEFT;
263 } else if (corner ==
264 prop_atoms.net_wm_moveresize_size_bottomright) {
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_TOPLEFT;
268 } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) {
269 cur_x = start_cw;
270 cur_y = start_ch + (e->xmotion.y_root - start_y);
271 lockcorner = OB_CORNER_TOPLEFT;
272 } else if (corner ==
273 prop_atoms.net_wm_moveresize_size_bottomleft) {
274 cur_x = start_cw - (e->xmotion.x_root - start_x);
275 cur_y = start_ch + (e->xmotion.y_root - start_y);
276 lockcorner = OB_CORNER_TOPRIGHT;
277 } else if (corner == prop_atoms.net_wm_moveresize_size_left) {
278 cur_x = start_cw - (e->xmotion.x_root - start_x);
279 cur_y = start_ch;
280 lockcorner = OB_CORNER_TOPRIGHT;
281 } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
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
286 g_assert_not_reached();
287
288 do_resize(TRUE);
289 }
290 } else if (e->type == KeyPress) {
291 if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE))
292 moveresize_end(TRUE);
293 else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN))
294 moveresize_end(FALSE);
295 else {
296 if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
297 int dx = 0, dy = 0, ox = cur_x, oy = cur_y;
298
299 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
300 dx = MAX(4, moveresize_client->size_inc.width);
301 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
302 dx = -MAX(4, moveresize_client->size_inc.width);
303 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
304 dy = MAX(4, moveresize_client->size_inc.height);
305 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
306 dy = -MAX(4, moveresize_client->size_inc.height);
307 else
308 return;
309
310 cur_x += dx;
311 cur_y += dy;
312 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
313 /* steal the motion events this causes */
314 XSync(ob_display, FALSE);
315 {
316 XEvent ce;
317 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
318 }
319
320 do_resize(FALSE);
321
322 /* because the cursor moves even though the window does
323 not nessesarily (resistance), this adjusts where the curor
324 thinks it started so that it keeps up with where the window
325 actually is */
326 start_x += dx - (cur_x - ox);
327 start_y += dy - (cur_y - oy);
328 } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
329 int dx = 0, dy = 0, ox = cur_x, oy = cur_y;
330 int opx, px, opy, py;
331
332 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
333 dx = 4;
334 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
335 dx = -4;
336 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
337 dy = 4;
338 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
339 dy = -4;
340 else
341 return;
342
343 cur_x += dx;
344 cur_y += dy;
345 screen_pointer_pos(&opx, &opy);
346 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
347 /* steal the motion events this causes */
348 XSync(ob_display, FALSE);
349 {
350 XEvent ce;
351 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
352 }
353 screen_pointer_pos(&px, &py);
354
355 do_move(FALSE);
356
357 /* because the cursor moves even though the window does
358 not nessesarily (resistance), this adjusts where the curor
359 thinks it started so that it keeps up with where the window
360 actually is */
361 start_x += (px - opx) - (cur_x - ox);
362 start_y += (py - opy) - (cur_y - oy);
363 }
364 }
365 }
366 }
This page took 0.049116 seconds and 4 git commands to generate.