]> Dogcows Code - chaz/openbox/blob - openbox/moveresize.c
fix7
[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) 2004 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, 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, cur);
168 grab_keyboard(TRUE);
169 }
170
171 void moveresize_end(gboolean cancel)
172 {
173 grab_keyboard(FALSE);
174 grab_pointer(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 /* 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);
209 }
210
211 static void do_resize(gboolean resist)
212 {
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;
218
219 if (resist)
220 resist_size_windows(moveresize_client, &cur_x, &cur_y, lockcorner);
221 resist_size_monitors(moveresize_client, &cur_x, &cur_y, lockcorner);
222
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;
227
228 client_configure(moveresize_client, lockcorner,
229 moveresize_client->area.x, moveresize_client->area.y,
230 cur_x, cur_y, TRUE, FALSE);
231
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))
238 )
239 popup_coords(moveresize_client, "%d x %d",
240 moveresize_client->logical_size.width,
241 moveresize_client->logical_size.height);
242 }
243
244 void moveresize_event(XEvent *e)
245 {
246 g_assert(moveresize_in_progress);
247
248 if (e->type == ButtonPress) {
249 if (!button) {
250 start_x = e->xbutton.x_root;
251 start_y = e->xbutton.y_root;
252 button = e->xbutton.button; /* this will end it now */
253 }
254 } else if (e->type == ButtonRelease) {
255 if (!button || e->xbutton.button == button) {
256 moveresize_end(FALSE);
257 }
258 } else if (e->type == MotionNotify) {
259 if (moving) {
260 cur_x = start_cx + e->xmotion.x_root - start_x;
261 cur_y = start_cy + e->xmotion.y_root - start_y;
262 do_move(TRUE);
263 } else {
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) {
269 cur_x = start_cw;
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);
278 cur_y = start_ch;
279 lockcorner = OB_CORNER_BOTTOMLEFT;
280 } else if (corner ==
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) {
286 cur_x = start_cw;
287 cur_y = start_ch + (e->xmotion.y_root - start_y);
288 lockcorner = OB_CORNER_TOPLEFT;
289 } else if (corner ==
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);
296 cur_y = start_ch;
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;
302 } else
303 g_assert_not_reached();
304
305 do_resize(TRUE);
306 }
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);
312 else {
313 if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
314 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
315
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);
324 else
325 return;
326
327 cur_x += dx;
328 cur_y += dy;
329 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
330 /* steal the motion events this causes */
331 XSync(ob_display, FALSE);
332 {
333 XEvent ce;
334 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
335 }
336
337 do_resize(FALSE);
338
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
342 actually is */
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;
348
349 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
350 dx = 4;
351 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
352 dx = -4;
353 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
354 dy = 4;
355 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
356 dy = -4;
357 else
358 return;
359
360 cur_x += dx;
361 cur_y += dy;
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);
366 {
367 XEvent ce;
368 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
369 }
370 screen_pointer_pos(&px, &py);
371
372 do_move(FALSE);
373
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
377 actually is */
378 start_x += (px - opx) - (cur_x - ox);
379 start_y += (py - opy) - (cur_y - oy);
380 }
381 }
382 }
383 }
This page took 0.049506 seconds and 4 git commands to generate.