]> Dogcows Code - chaz/openbox/blob - openbox/moveresize.c
fix resizing when drawContents is off, and I think an ifdef was a bit too high up
[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-2007 Dana 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 "event.h"
32 #include "debug.h"
33 #include "extensions.h"
34 #include "render/render.h"
35 #include "render/theme.h"
36
37 #include <X11/Xlib.h>
38 #include <glib.h>
39
40 gboolean moveresize_in_progress = FALSE;
41 ObClient *moveresize_client = NULL;
42 #ifdef SYNC
43 XSyncAlarm moveresize_alarm = None;
44 #endif
45
46 static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */
47
48 static gint start_x, start_y, start_cx, start_cy, start_cw, start_ch;
49 static gint cur_x, cur_y;
50 static guint button;
51 static guint32 corner;
52 static ObCorner lockcorner;
53 #ifdef SYNC
54 static gboolean waiting_for_sync;
55 #endif
56
57 static ObPopup *popup = NULL;
58
59 static void client_dest(ObClient *client, gpointer data)
60 {
61 if (moveresize_client == client)
62 moveresize_end(TRUE);
63 }
64
65 void moveresize_startup(gboolean reconfig)
66 {
67 popup = popup_new(FALSE);
68
69 if (!reconfig)
70 client_add_destructor(client_dest, NULL);
71 }
72
73 void moveresize_shutdown(gboolean reconfig)
74 {
75 if (!reconfig) {
76 if (moveresize_in_progress)
77 moveresize_end(FALSE);
78 client_remove_destructor(client_dest);
79 }
80
81 popup_free(popup);
82 popup = NULL;
83 }
84
85 static void popup_coords(ObClient *c, const gchar *format, gint a, gint b)
86 {
87 gchar *text;
88
89 text = g_strdup_printf(format, a, b);
90 if (config_resize_popup_pos == 1) /* == "Top" */
91 popup_position(popup, SouthGravity,
92 c->frame->area.x
93 + c->frame->area.width/2,
94 c->frame->area.y - ob_rr_theme->fbwidth);
95 else /* == "Center" */
96 popup_position(popup, CenterGravity,
97 c->frame->area.x + c->frame->size.left +
98 c->area.width / 2,
99 c->frame->area.y + c->frame->size.top +
100 c->area.height / 2);
101 popup_show(popup, text);
102 g_free(text);
103 }
104
105 void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
106 {
107 ObCursor cur;
108
109 moving = (cnr == prop_atoms.net_wm_moveresize_move ||
110 cnr == prop_atoms.net_wm_moveresize_move_keyboard);
111
112 if (moveresize_in_progress || !c->frame->visible ||
113 !(moving ?
114 (c->functions & OB_CLIENT_FUNC_MOVE) :
115 (c->functions & OB_CLIENT_FUNC_RESIZE)))
116 return;
117
118 moveresize_client = c;
119 start_cx = c->frame->area.x;
120 start_cy = c->frame->area.y;
121 /* these adjustments for the size_inc make resizing a terminal more
122 friendly. you essentially start the resize in the middle of the
123 increment instead of at 0, so you have to move half an increment
124 either way instead of a full increment one and 1 px the other. and this
125 is one large mother fucking comment. */
126 start_cw = c->area.width + c->size_inc.width / 2;
127 start_ch = c->area.height + c->size_inc.height / 2;
128 start_x = x;
129 start_y = y;
130 corner = cnr;
131 button = b;
132
133 /*
134 have to change start_cx and start_cy if going to do this..
135 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
136 corner == prop_atoms.net_wm_moveresize_size_keyboard)
137 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
138 c->area.width / 2, c->area.height / 2);
139 */
140
141 if (moving) {
142 cur_x = start_cx;
143 cur_y = start_cy;
144 } else {
145 cur_x = start_cw;
146 cur_y = start_ch;
147 }
148
149 moveresize_in_progress = TRUE;
150
151 if (corner == prop_atoms.net_wm_moveresize_size_topleft)
152 cur = OB_CURSOR_NORTHWEST;
153 else if (corner == prop_atoms.net_wm_moveresize_size_top)
154 cur = OB_CURSOR_NORTH;
155 else if (corner == prop_atoms.net_wm_moveresize_size_topright)
156 cur = OB_CURSOR_NORTHEAST;
157 else if (corner == prop_atoms.net_wm_moveresize_size_right)
158 cur = OB_CURSOR_EAST;
159 else if (corner == prop_atoms.net_wm_moveresize_size_bottomright)
160 cur = OB_CURSOR_SOUTHEAST;
161 else if (corner == prop_atoms.net_wm_moveresize_size_bottom)
162 cur = OB_CURSOR_SOUTH;
163 else if (corner == prop_atoms.net_wm_moveresize_size_bottomleft)
164 cur = OB_CURSOR_SOUTHWEST;
165 else if (corner == prop_atoms.net_wm_moveresize_size_left)
166 cur = OB_CURSOR_WEST;
167 else if (corner == prop_atoms.net_wm_moveresize_size_keyboard)
168 cur = OB_CURSOR_SOUTHEAST;
169 else if (corner == prop_atoms.net_wm_moveresize_move)
170 cur = OB_CURSOR_MOVE;
171 else if (corner == prop_atoms.net_wm_moveresize_move_keyboard)
172 cur = OB_CURSOR_MOVE;
173 else
174 g_assert_not_reached();
175
176 #ifdef SYNC
177 if (config_resize_redraw && !moving && extensions_shape &&
178 moveresize_client->sync_request && moveresize_client->sync_counter)
179 {
180 /* Initialize values for the resize syncing, and create an alarm for
181 the client's xsync counter */
182
183 XSyncValue val;
184 XSyncAlarmAttributes aa;
185
186 /* set the counter to an initial value */
187 XSyncIntToValue(&val, 0);
188 XSyncSetCounter(ob_display, moveresize_client->sync_counter, val);
189
190 /* this will be incremented when we tell the client what we're
191 looking for */
192 moveresize_client->sync_counter_value = 0;
193
194 /* the next sequence we're waiting for with the alarm */
195 XSyncIntToValue(&val, 1);
196
197 /* set an alarm on the counter */
198 aa.trigger.counter = moveresize_client->sync_counter;
199 aa.trigger.wait_value = val;
200 aa.trigger.value_type = XSyncAbsolute;
201 aa.trigger.test_type = XSyncPositiveTransition;
202 aa.events = True;
203 XSyncIntToValue(&aa.delta, 1);
204 moveresize_alarm = XSyncCreateAlarm(ob_display,
205 XSyncCACounter |
206 XSyncCAValue |
207 XSyncCAValueType |
208 XSyncCATestType |
209 XSyncCADelta |
210 XSyncCAEvents,
211 &aa);
212
213 waiting_for_sync = FALSE;
214 }
215 #endif
216
217 grab_pointer(TRUE, FALSE, cur);
218 grab_keyboard(TRUE);
219 }
220
221 void moveresize_end(gboolean cancel)
222 {
223 grab_keyboard(FALSE);
224 grab_pointer(FALSE, FALSE, OB_CURSOR_NONE);
225
226 popup_hide(popup);
227
228 if (moving) {
229 client_move(moveresize_client,
230 (cancel ? start_cx : cur_x),
231 (cancel ? start_cy : cur_y));
232 } else {
233 #ifdef SYNC
234 /* turn off the alarm */
235 if (moveresize_alarm != None) {
236 XSyncDestroyAlarm(ob_display, moveresize_alarm);
237 moveresize_alarm = None;
238 }
239 #endif
240
241 client_configure(moveresize_client, lockcorner,
242 moveresize_client->area.x,
243 moveresize_client->area.y,
244 (cancel ? start_cw : cur_x),
245 (cancel ? start_ch : cur_y), TRUE, TRUE);
246 }
247
248 moveresize_in_progress = FALSE;
249 moveresize_client = NULL;
250 }
251
252 static void do_move(gboolean resist)
253 {
254 if (resist) {
255 resist_move_windows(moveresize_client, &cur_x, &cur_y);
256 resist_move_monitors(moveresize_client, &cur_x, &cur_y);
257 }
258
259 /* get where the client should be */
260 frame_frame_gravity(moveresize_client->frame, &cur_x, &cur_y);
261 client_configure(moveresize_client, OB_CORNER_TOPLEFT, cur_x, cur_y,
262 moveresize_client->area.width,
263 moveresize_client->area.height, TRUE, FALSE);
264 if (config_resize_popup_show == 2) /* == "Always" */
265 popup_coords(moveresize_client, "%d x %d",
266 moveresize_client->frame->area.x,
267 moveresize_client->frame->area.y);
268 }
269
270 static void do_resize()
271 {
272 gint x, y, w, h, lw, lh;
273
274 /* see if it is actually going to resize */
275 x = moveresize_client->area.x;
276 y = moveresize_client->area.y;
277 w = cur_x;
278 h = cur_y;
279 client_try_configure(moveresize_client, lockcorner, &x, &y, &w, &h,
280 &lw, &lh, TRUE);
281 if (w == moveresize_client->area.width &&
282 h == moveresize_client->area.height)
283 {
284 return;
285 }
286
287 #ifdef SYNC
288 if (config_resize_redraw && extensions_sync &&
289 moveresize_client->sync_request && moveresize_client->sync_counter)
290 {
291 XEvent ce;
292 XSyncValue val;
293
294 /* are we already waiting for the sync counter to catch up? */
295 if (waiting_for_sync)
296 return;
297
298 /* increment the value we're waiting for */
299 ++moveresize_client->sync_counter_value;
300 XSyncIntToValue(&val, moveresize_client->sync_counter_value);
301
302 /* tell the client what we're waiting for */
303 ce.xclient.type = ClientMessage;
304 ce.xclient.message_type = prop_atoms.wm_protocols;
305 ce.xclient.display = ob_display;
306 ce.xclient.window = moveresize_client->window;
307 ce.xclient.format = 32;
308 ce.xclient.data.l[0] = prop_atoms.net_wm_sync_request;
309 ce.xclient.data.l[1] = event_curtime;
310 ce.xclient.data.l[2] = XSyncValueLow32(val);
311 ce.xclient.data.l[3] = XSyncValueHigh32(val);
312 ce.xclient.data.l[4] = 0l;
313 XSendEvent(ob_display, moveresize_client->window, FALSE,
314 NoEventMask, &ce);
315
316 waiting_for_sync = TRUE;
317 }
318 #endif
319
320 client_configure(moveresize_client, lockcorner,
321 moveresize_client->area.x, moveresize_client->area.y,
322 cur_x, cur_y, TRUE, FALSE);
323
324 /* this would be better with a fixed width font ... XXX can do it better
325 if there are 2 text boxes */
326 if (config_resize_popup_show == 2 || /* == "Always" */
327 (config_resize_popup_show == 1 && /* == "Nonpixel" */
328 (moveresize_client->size_inc.width > 1 ||
329 moveresize_client->size_inc.height > 1))
330 )
331 popup_coords(moveresize_client, "%d x %d",
332 moveresize_client->logical_size.width,
333 moveresize_client->logical_size.height);
334 }
335
336 static void calc_resize(gboolean resist)
337 {
338 /* resist_size_* needs the frame size */
339 cur_x += moveresize_client->frame->size.left +
340 moveresize_client->frame->size.right;
341 cur_y += moveresize_client->frame->size.top +
342 moveresize_client->frame->size.bottom;
343
344 if (resist) {
345 resist_size_windows(moveresize_client, &cur_x, &cur_y, lockcorner);
346 resist_size_monitors(moveresize_client, &cur_x, &cur_y, lockcorner);
347 }
348
349 cur_x -= moveresize_client->frame->size.left +
350 moveresize_client->frame->size.right;
351 cur_y -= moveresize_client->frame->size.top +
352 moveresize_client->frame->size.bottom;
353 }
354
355 void moveresize_event(XEvent *e)
356 {
357 g_assert(moveresize_in_progress);
358
359 if (e->type == ButtonPress) {
360 if (!button) {
361 start_x = e->xbutton.x_root;
362 start_y = e->xbutton.y_root;
363 button = e->xbutton.button; /* this will end it now */
364 }
365 } else if (e->type == ButtonRelease) {
366 if (!button || e->xbutton.button == button) {
367 moveresize_end(FALSE);
368 }
369 } else if (e->type == MotionNotify) {
370 if (moving) {
371 cur_x = start_cx + e->xmotion.x_root - start_x;
372 cur_y = start_cy + e->xmotion.y_root - start_y;
373 do_move(TRUE);
374 } else {
375 if (corner == prop_atoms.net_wm_moveresize_size_topleft) {
376 cur_x = start_cw - (e->xmotion.x_root - start_x);
377 cur_y = start_ch - (e->xmotion.y_root - start_y);
378 lockcorner = OB_CORNER_BOTTOMRIGHT;
379 } else if (corner == prop_atoms.net_wm_moveresize_size_top) {
380 cur_x = start_cw;
381 cur_y = start_ch - (e->xmotion.y_root - start_y);
382 lockcorner = OB_CORNER_BOTTOMRIGHT;
383 } else if (corner == prop_atoms.net_wm_moveresize_size_topright) {
384 cur_x = start_cw + (e->xmotion.x_root - start_x);
385 cur_y = start_ch - (e->xmotion.y_root - start_y);
386 lockcorner = OB_CORNER_BOTTOMLEFT;
387 } else if (corner == prop_atoms.net_wm_moveresize_size_right) {
388 cur_x = start_cw + (e->xmotion.x_root - start_x);
389 cur_y = start_ch;
390 lockcorner = OB_CORNER_BOTTOMLEFT;
391 } else if (corner ==
392 prop_atoms.net_wm_moveresize_size_bottomright) {
393 cur_x = start_cw + (e->xmotion.x_root - start_x);
394 cur_y = start_ch + (e->xmotion.y_root - start_y);
395 lockcorner = OB_CORNER_TOPLEFT;
396 } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) {
397 cur_x = start_cw;
398 cur_y = start_ch + (e->xmotion.y_root - start_y);
399 lockcorner = OB_CORNER_TOPLEFT;
400 } else if (corner ==
401 prop_atoms.net_wm_moveresize_size_bottomleft) {
402 cur_x = start_cw - (e->xmotion.x_root - start_x);
403 cur_y = start_ch + (e->xmotion.y_root - start_y);
404 lockcorner = OB_CORNER_TOPRIGHT;
405 } else if (corner == prop_atoms.net_wm_moveresize_size_left) {
406 cur_x = start_cw - (e->xmotion.x_root - start_x);
407 cur_y = start_ch;
408 lockcorner = OB_CORNER_TOPRIGHT;
409 } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
410 cur_x = start_cw + (e->xmotion.x_root - start_x);
411 cur_y = start_ch + (e->xmotion.y_root - start_y);
412 lockcorner = OB_CORNER_TOPLEFT;
413 } else
414 g_assert_not_reached();
415
416 calc_resize(TRUE);
417 do_resize();
418 }
419 } else if (e->type == KeyPress) {
420 if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE))
421 moveresize_end(TRUE);
422 else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN))
423 moveresize_end(FALSE);
424 else {
425 if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
426 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
427
428 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
429 dx = MAX(4, moveresize_client->size_inc.width);
430 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
431 dx = -MAX(4, moveresize_client->size_inc.width);
432 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
433 dy = MAX(4, moveresize_client->size_inc.height);
434 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
435 dy = -MAX(4, moveresize_client->size_inc.height);
436 else
437 return;
438
439 cur_x += dx;
440 cur_y += dy;
441 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
442 /* steal the motion events this causes */
443 XSync(ob_display, FALSE);
444 {
445 XEvent ce;
446 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
447 }
448
449 do_resize(FALSE);
450
451 /* because the cursor moves even though the window does
452 not nessesarily (resistance), this adjusts where the curor
453 thinks it started so that it keeps up with where the window
454 actually is */
455 start_x += dx - (cur_x - ox);
456 start_y += dy - (cur_y - oy);
457 } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
458 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
459 gint opx, px, opy, py;
460
461 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
462 dx = 4;
463 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
464 dx = -4;
465 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
466 dy = 4;
467 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
468 dy = -4;
469 else
470 return;
471
472 cur_x += dx;
473 cur_y += dy;
474 screen_pointer_pos(&opx, &opy);
475 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
476 /* steal the motion events this causes */
477 XSync(ob_display, FALSE);
478 {
479 XEvent ce;
480 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
481 }
482 screen_pointer_pos(&px, &py);
483
484 do_move(FALSE);
485
486 /* because the cursor moves even though the window does
487 not nessesarily (resistance), this adjusts where the curor
488 thinks it started so that it keeps up with where the window
489 actually is */
490 start_x += (px - opx) - (cur_x - ox);
491 start_y += (py - opy) - (cur_y - oy);
492 }
493 }
494 }
495 #ifdef SYNC
496 else if (e->type == extensions_sync_event_basep + XSyncAlarmNotify)
497 {
498 waiting_for_sync = FALSE; /* we got our sync... */
499 do_resize(); /* ...so try resize if there is more change pending */
500 }
501 #endif
502 }
This page took 0.05778 seconds and 5 git commands to generate.