]> Dogcows Code - chaz/openbox/blob - openbox/moveresize.c
comments for life
[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) 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 gint start_x, start_y, start_cx, start_cy, start_cw, start_ch;
42 static gint 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(ObClient *client, gpointer data)
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, NULL);
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, gchar *format, gint a, gint b)
76 {
77 gchar *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, gint x, gint y, guint b, guint32 cnr)
90 {
91 ObCursor cur;
92
93 moving = (cnr == prop_atoms.net_wm_moveresize_move ||
94 cnr == prop_atoms.net_wm_moveresize_move_keyboard);
95
96 if (moveresize_in_progress || !c->frame->visible ||
97 !(moving ?
98 (c->functions & OB_CLIENT_FUNC_MOVE) :
99 (c->functions & OB_CLIENT_FUNC_RESIZE)))
100 return;
101
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;
112 start_x = x;
113 start_y = y;
114 corner = cnr;
115 button = b;
116
117 /*
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);
123 */
124
125 if (moving) {
126 cur_x = start_cx;
127 cur_y = start_cy;
128 } else {
129 cur_x = start_cw;
130 cur_y = start_ch;
131 }
132
133 moveresize_in_progress = TRUE;
134
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;
157 else
158 g_assert_not_reached();
159
160 grab_pointer(TRUE, cur);
161 grab_keyboard(TRUE);
162 }
163
164 void moveresize_end(gboolean cancel)
165 {
166 grab_keyboard(FALSE);
167 grab_pointer(FALSE, OB_CURSOR_NONE);
168
169 popup_hide(popup);
170
171 if (moving) {
172 client_move(moveresize_client,
173 (cancel ? start_cx : cur_x),
174 (cancel ? start_cy : cur_y));
175 } else {
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);
181 }
182
183 moveresize_in_progress = FALSE;
184 moveresize_client = NULL;
185 }
186
187 static void do_move(gboolean resist)
188 {
189 if (resist)
190 resist_move_windows(moveresize_client, &cur_x, &cur_y);
191 resist_move_monitors(moveresize_client, &cur_x, &cur_y);
192
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);
202 }
203
204 static void do_resize(gboolean resist)
205 {
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;
211
212 if (resist)
213 resist_size_windows(moveresize_client, &cur_x, &cur_y, lockcorner);
214 resist_size_monitors(moveresize_client, &cur_x, &cur_y, lockcorner);
215
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;
220
221 client_configure(moveresize_client, lockcorner,
222 moveresize_client->area.x, moveresize_client->area.y,
223 cur_x, cur_y, TRUE, FALSE);
224
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))
231 )
232 popup_coords(moveresize_client, "%d x %d",
233 moveresize_client->logical_size.width,
234 moveresize_client->logical_size.height);
235 }
236
237 void moveresize_event(XEvent *e)
238 {
239 g_assert(moveresize_in_progress);
240
241 if (e->type == ButtonPress) {
242 if (!button) {
243 start_x = e->xbutton.x_root;
244 start_y = e->xbutton.y_root;
245 button = e->xbutton.button; /* this will end it now */
246 }
247 } else if (e->type == ButtonRelease) {
248 if (!button || e->xbutton.button == button) {
249 moveresize_end(FALSE);
250 }
251 } else if (e->type == MotionNotify) {
252 if (moving) {
253 cur_x = start_cx + e->xmotion.x_root - start_x;
254 cur_y = start_cy + e->xmotion.y_root - start_y;
255 do_move(TRUE);
256 } else {
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) {
262 cur_x = start_cw;
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);
271 cur_y = start_ch;
272 lockcorner = OB_CORNER_BOTTOMLEFT;
273 } else if (corner ==
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) {
279 cur_x = start_cw;
280 cur_y = start_ch + (e->xmotion.y_root - start_y);
281 lockcorner = OB_CORNER_TOPLEFT;
282 } else if (corner ==
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);
289 cur_y = start_ch;
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;
295 } else
296 g_assert_not_reached();
297
298 do_resize(TRUE);
299 }
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);
305 else {
306 if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
307 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
308
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);
317 else
318 return;
319
320 cur_x += dx;
321 cur_y += dy;
322 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
323 /* steal the motion events this causes */
324 XSync(ob_display, FALSE);
325 {
326 XEvent ce;
327 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
328 }
329
330 do_resize(FALSE);
331
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
335 actually is */
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;
341
342 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
343 dx = 4;
344 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
345 dx = -4;
346 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
347 dy = 4;
348 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
349 dy = -4;
350 else
351 return;
352
353 cur_x += dx;
354 cur_y += dy;
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);
359 {
360 XEvent ce;
361 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
362 }
363 screen_pointer_pos(&px, &py);
364
365 do_move(FALSE);
366
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
370 actually is */
371 start_x += (px - opx) - (cur_x - ox);
372 start_y += (py - opy) - (cur_y - oy);
373 }
374 }
375 }
376 }
This page took 0.060621 seconds and 5 git commands to generate.