]> Dogcows Code - chaz/openbox/blob - openbox/moveresize.c
6cab52262dcea9737332d42b88d523bf952a1336
[chaz/openbox] / openbox / moveresize.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 moveresize.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003 Ben Jansens
6
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.
11
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.
16
17 See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "grab.h"
21 #include "framerender.h"
22 #include "screen.h"
23 #include "prop.h"
24 #include "client.h"
25 #include "frame.h"
26 #include "openbox.h"
27 #include "resist.h"
28 #include "popup.h"
29 #include "moveresize.h"
30 #include "config.h"
31 #include "render/render.h"
32 #include "render/theme.h"
33
34 #include <X11/Xlib.h>
35 #include <glib.h>
36
37 gboolean moveresize_in_progress = FALSE;
38 ObClient *moveresize_client = NULL;
39
40 static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */
41
42 static gint start_x, start_y, start_cx, start_cy, start_cw, start_ch;
43 static gint cur_x, cur_y;
44 static guint button;
45 static guint32 corner;
46 static ObCorner lockcorner;
47
48 static ObPopup *popup = NULL;
49
50 static void client_dest(ObClient *client, gpointer data)
51 {
52 if (moveresize_client == client)
53 moveresize_end(TRUE);
54 }
55
56 void moveresize_startup(gboolean reconfig)
57 {
58 popup = popup_new(FALSE);
59
60 if (!reconfig)
61 client_add_destructor(client_dest, NULL);
62 }
63
64 void moveresize_shutdown(gboolean reconfig)
65 {
66 if (!reconfig) {
67 if (moveresize_in_progress)
68 moveresize_end(FALSE);
69 client_remove_destructor(client_dest);
70 }
71
72 popup_free(popup);
73 popup = NULL;
74 }
75
76 static void popup_coords(ObClient *c, const gchar *format, gint a, gint b)
77 {
78 gchar *text;
79
80 text = g_strdup_printf(format, a, b);
81 if (config_resize_popup_pos == 1) /* == "Top" */
82 popup_position(popup, SouthGravity,
83 c->frame->area.x
84 + c->frame->area.width/2,
85 c->frame->area.y);
86 else /* == "Center" */
87 popup_position(popup, CenterGravity,
88 c->frame->area.x + c->frame->size.left +
89 c->area.width / 2,
90 c->frame->area.y + c->frame->size.top +
91 c->area.height / 2);
92 popup_show(popup, text);
93 g_free(text);
94 }
95
96 void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
97 {
98 ObCursor cur;
99
100 moving = (cnr == prop_atoms.net_wm_moveresize_move ||
101 cnr == prop_atoms.net_wm_moveresize_move_keyboard);
102
103 if (moveresize_in_progress || !c->frame->visible ||
104 !(moving ?
105 (c->functions & OB_CLIENT_FUNC_MOVE) :
106 (c->functions & OB_CLIENT_FUNC_RESIZE)))
107 return;
108
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;
119 start_x = x;
120 start_y = y;
121 corner = cnr;
122 button = b;
123
124 /*
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);
130 */
131
132 if (moving) {
133 cur_x = start_cx;
134 cur_y = start_cy;
135 } else {
136 cur_x = start_cw;
137 cur_y = start_ch;
138 }
139
140 moveresize_in_progress = TRUE;
141
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;
164 else
165 g_assert_not_reached();
166
167 grab_pointer(TRUE, FALSE, cur);
168 grab_keyboard(TRUE);
169 }
170
171 void moveresize_end(gboolean cancel)
172 {
173 grab_keyboard(FALSE);
174 grab_pointer(FALSE, FALSE, OB_CURSOR_NONE);
175
176 popup_hide(popup);
177
178 if (moving) {
179 client_move(moveresize_client,
180 (cancel ? start_cx : cur_x),
181 (cancel ? start_cy : cur_y));
182 } else {
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);
188 }
189
190 moveresize_in_progress = FALSE;
191 moveresize_client = NULL;
192 }
193
194 static void do_move(gboolean resist)
195 {
196 if (resist) {
197 resist_move_windows(moveresize_client, &cur_x, &cur_y);
198 resist_move_monitors(moveresize_client, &cur_x, &cur_y);
199 }
200
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);
210 }
211
212 static void do_resize(gboolean resist)
213 {
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;
219
220 if (resist) {
221 resist_size_windows(moveresize_client, &cur_x, &cur_y, lockcorner);
222 resist_size_monitors(moveresize_client, &cur_x, &cur_y, lockcorner);
223 }
224
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;
229
230 client_configure(moveresize_client, lockcorner,
231 moveresize_client->area.x, moveresize_client->area.y,
232 cur_x, cur_y, TRUE, FALSE);
233
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))
240 )
241 popup_coords(moveresize_client, "%d x %d",
242 moveresize_client->logical_size.width,
243 moveresize_client->logical_size.height);
244 }
245
246 void moveresize_event(XEvent *e)
247 {
248 g_assert(moveresize_in_progress);
249
250 if (e->type == ButtonPress) {
251 if (!button) {
252 start_x = e->xbutton.x_root;
253 start_y = e->xbutton.y_root;
254 button = e->xbutton.button; /* this will end it now */
255 }
256 } else if (e->type == ButtonRelease) {
257 if (!button || e->xbutton.button == button) {
258 moveresize_end(FALSE);
259 }
260 } else if (e->type == MotionNotify) {
261 if (moving) {
262 cur_x = start_cx + e->xmotion.x_root - start_x;
263 cur_y = start_cy + e->xmotion.y_root - start_y;
264 do_move(TRUE);
265 } else {
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) {
271 cur_x = start_cw;
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);
280 cur_y = start_ch;
281 lockcorner = OB_CORNER_BOTTOMLEFT;
282 } else if (corner ==
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) {
288 cur_x = start_cw;
289 cur_y = start_ch + (e->xmotion.y_root - start_y);
290 lockcorner = OB_CORNER_TOPLEFT;
291 } else if (corner ==
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);
298 cur_y = start_ch;
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;
304 } else
305 g_assert_not_reached();
306
307 do_resize(TRUE);
308 }
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);
314 else {
315 if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
316 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
317
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);
326 else
327 return;
328
329 cur_x += dx;
330 cur_y += dy;
331 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
332 /* steal the motion events this causes */
333 XSync(ob_display, FALSE);
334 {
335 XEvent ce;
336 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
337 }
338
339 do_resize(FALSE);
340
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
344 actually is */
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;
350
351 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
352 dx = 4;
353 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
354 dx = -4;
355 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
356 dy = 4;
357 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
358 dy = -4;
359 else
360 return;
361
362 cur_x += dx;
363 cur_y += dy;
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);
368 {
369 XEvent ce;
370 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
371 }
372 screen_pointer_pos(&px, &py);
373
374 do_move(FALSE);
375
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
379 actually is */
380 start_x += (px - opx) - (cur_x - ox);
381 start_y += (py - opy) - (cur_y - oy);
382 }
383 }
384 }
385 }
This page took 0.048256 seconds and 3 git commands to generate.