]> Dogcows Code - chaz/openbox/blob - openbox/moveresize.c
don't resist when resizing terminals with the keyboard
[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 "mainloop.h"
29 #include "modkeys.h"
30 #include "popup.h"
31 #include "moveresize.h"
32 #include "config.h"
33 #include "event.h"
34 #include "debug.h"
35 #include "extensions.h"
36 #include "render/render.h"
37 #include "render/theme.h"
38
39 #include <X11/Xlib.h>
40 #include <glib.h>
41
42 /* how far windows move and resize with the keyboard arrows */
43 #define KEY_DIST 8
44
45 gboolean moveresize_in_progress = FALSE;
46 ObClient *moveresize_client = NULL;
47 #ifdef SYNC
48 XSyncAlarm moveresize_alarm = None;
49 #endif
50
51 static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */
52
53 static gint start_x, start_y, start_cx, start_cy, start_cw, start_ch;
54 static gint cur_x, cur_y, cur_w, cur_h;
55 static guint button;
56 static guint32 corner;
57 static ObCorner lockcorner;
58 static ObDirection edge_warp_dir = -1;
59 static ObDirection key_resize_edge = -1;
60 #ifdef SYNC
61 static gboolean waiting_for_sync;
62 #endif
63
64 static ObPopup *popup = NULL;
65
66 static void do_edge_warp(gint x, gint y);
67 static void cancel_edge_warp();
68 #ifdef SYNC
69 static gboolean sync_timeout_func(gpointer data);
70 #endif
71
72 static void client_dest(ObClient *client, gpointer data)
73 {
74 if (moveresize_client == client)
75 moveresize_end(TRUE);
76 }
77
78 void moveresize_startup(gboolean reconfig)
79 {
80 popup = popup_new(FALSE);
81 popup_set_text_align(popup, RR_JUSTIFY_CENTER);
82
83 if (!reconfig)
84 client_add_destroy_notify(client_dest, NULL);
85 }
86
87 void moveresize_shutdown(gboolean reconfig)
88 {
89 if (!reconfig) {
90 if (moveresize_in_progress)
91 moveresize_end(FALSE);
92 client_remove_destroy_notify(client_dest);
93 }
94
95 popup_free(popup);
96 popup = NULL;
97 }
98
99 static void popup_coords(ObClient *c, const gchar *format, gint a, gint b)
100 {
101 gchar *text;
102
103 text = g_strdup_printf(format, a, b);
104 if (config_resize_popup_pos == 1) /* == "Top" */
105 popup_position(popup, SouthGravity,
106 c->frame->area.x
107 + c->frame->area.width/2,
108 c->frame->area.y - ob_rr_theme->fbwidth);
109 else /* == "Center" */
110 popup_position(popup, CenterGravity,
111 c->frame->area.x + c->frame->size.left +
112 c->area.width / 2,
113 c->frame->area.y + c->frame->size.top +
114 c->area.height / 2);
115 popup_show(popup, text);
116 g_free(text);
117 }
118
119 void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
120 {
121 ObCursor cur;
122 gboolean mv = (cnr == prop_atoms.net_wm_moveresize_move ||
123 cnr == prop_atoms.net_wm_moveresize_move_keyboard);
124
125 if (moveresize_in_progress || !c->frame->visible ||
126 !(mv ?
127 (c->functions & OB_CLIENT_FUNC_MOVE) :
128 (c->functions & OB_CLIENT_FUNC_RESIZE)))
129 return;
130
131 if (cnr == prop_atoms.net_wm_moveresize_size_topleft)
132 cur = OB_CURSOR_NORTHWEST;
133 else if (cnr == prop_atoms.net_wm_moveresize_size_top)
134 cur = OB_CURSOR_NORTH;
135 else if (cnr == prop_atoms.net_wm_moveresize_size_topright)
136 cur = OB_CURSOR_NORTHEAST;
137 else if (cnr == prop_atoms.net_wm_moveresize_size_right)
138 cur = OB_CURSOR_EAST;
139 else if (cnr == prop_atoms.net_wm_moveresize_size_bottomright)
140 cur = OB_CURSOR_SOUTHEAST;
141 else if (cnr == prop_atoms.net_wm_moveresize_size_bottom)
142 cur = OB_CURSOR_SOUTH;
143 else if (cnr == prop_atoms.net_wm_moveresize_size_bottomleft)
144 cur = OB_CURSOR_SOUTHWEST;
145 else if (cnr == prop_atoms.net_wm_moveresize_size_left)
146 cur = OB_CURSOR_WEST;
147 else if (cnr == prop_atoms.net_wm_moveresize_size_keyboard)
148 cur = OB_CURSOR_SOUTHEAST;
149 else if (cnr == prop_atoms.net_wm_moveresize_move)
150 cur = OB_CURSOR_MOVE;
151 else if (cnr == prop_atoms.net_wm_moveresize_move_keyboard)
152 cur = OB_CURSOR_MOVE;
153 else
154 g_assert_not_reached();
155
156 /* keep the pointer bounded to the screen for move/resize */
157 if (!grab_pointer(FALSE, TRUE, cur))
158 return;
159 if (!grab_keyboard()) {
160 ungrab_pointer();
161 return;
162 }
163
164 frame_end_iconify_animation(c->frame);
165
166 moving = mv;
167 moveresize_client = c;
168 start_cx = c->area.x;
169 start_cy = c->area.y;
170 start_cw = c->area.width;
171 start_ch = c->area.height;
172 /* these adjustments for the size_inc make resizing a terminal more
173 friendly. you essentially start the resize in the middle of the
174 increment instead of at 0, so you have to move half an increment
175 either way instead of a full increment one and 1 px the other. */
176 start_x = x - (mv ? 0 : c->size_inc.width / 2);
177 start_y = y - (mv ? 0 : c->size_inc.height / 2);
178 corner = cnr;
179 button = b;
180 key_resize_edge = -1;
181
182 /*
183 have to change start_cx and start_cy if going to do this..
184 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
185 corner == prop_atoms.net_wm_moveresize_size_keyboard)
186 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
187 c->area.width / 2, c->area.height / 2);
188 */
189
190 cur_x = start_cx;
191 cur_y = start_cy;
192 cur_w = start_cw;
193 cur_h = start_ch;
194
195 moveresize_in_progress = TRUE;
196
197 #ifdef SYNC
198 if (config_resize_redraw && !moving && extensions_sync &&
199 moveresize_client->sync_request && moveresize_client->sync_counter)
200 {
201 /* Initialize values for the resize syncing, and create an alarm for
202 the client's xsync counter */
203
204 XSyncValue val;
205 XSyncAlarmAttributes aa;
206
207 /* set the counter to an initial value */
208 XSyncIntToValue(&val, 0);
209 XSyncSetCounter(ob_display, moveresize_client->sync_counter, val);
210
211 /* this will be incremented when we tell the client what we're
212 looking for */
213 moveresize_client->sync_counter_value = 0;
214
215 /* the next sequence we're waiting for with the alarm */
216 XSyncIntToValue(&val, 1);
217
218 /* set an alarm on the counter */
219 aa.trigger.counter = moveresize_client->sync_counter;
220 aa.trigger.wait_value = val;
221 aa.trigger.value_type = XSyncAbsolute;
222 aa.trigger.test_type = XSyncPositiveTransition;
223 aa.events = True;
224 XSyncIntToValue(&aa.delta, 1);
225 moveresize_alarm = XSyncCreateAlarm(ob_display,
226 XSyncCACounter |
227 XSyncCAValue |
228 XSyncCAValueType |
229 XSyncCATestType |
230 XSyncCADelta |
231 XSyncCAEvents,
232 &aa);
233
234 waiting_for_sync = FALSE;
235 }
236 #endif
237 }
238
239 void moveresize_end(gboolean cancel)
240 {
241 ungrab_keyboard();
242 ungrab_pointer();
243
244 popup_hide(popup);
245
246 if (moving) {
247 client_move(moveresize_client,
248 (cancel ? start_cx : cur_x),
249 (cancel ? start_cy : cur_y));
250 } else {
251 #ifdef SYNC
252 /* turn off the alarm */
253 if (moveresize_alarm != None) {
254 XSyncDestroyAlarm(ob_display, moveresize_alarm);
255 moveresize_alarm = None;
256 }
257
258 ob_main_loop_timeout_remove(ob_main_loop, sync_timeout_func);
259 #endif
260
261 client_configure(moveresize_client,
262 (cancel ? start_cx : cur_x),
263 (cancel ? start_cy : cur_y),
264 (cancel ? start_cw : cur_w),
265 (cancel ? start_ch : cur_h),
266 TRUE, TRUE, FALSE);
267 }
268
269 /* dont edge warp after its ended */
270 cancel_edge_warp();
271
272 moveresize_in_progress = FALSE;
273 moveresize_client = NULL;
274 }
275
276 static void do_move(gboolean keyboard, gint keydist)
277 {
278 gint resist;
279
280 if (keyboard) resist = keydist - 1; /* resist for one key press */
281 else resist = config_resist_win;
282 resist_move_windows(moveresize_client, resist, &cur_x, &cur_y);
283 if (!keyboard) resist = config_resist_edge;
284 resist_move_monitors(moveresize_client, resist, &cur_x, &cur_y);
285
286 client_configure(moveresize_client, cur_x, cur_y, cur_w, cur_h,
287 TRUE, FALSE, FALSE);
288 if (config_resize_popup_show == 2) /* == "Always" */
289 popup_coords(moveresize_client, "%d x %d",
290 moveresize_client->frame->area.x,
291 moveresize_client->frame->area.y);
292 }
293
294
295 static void do_resize()
296 {
297 gint x, y, w, h, lw, lh;
298
299 /* see if it is actually going to resize */
300 x = 0;
301 y = 0;
302 w = cur_w;
303 h = cur_h;
304 client_try_configure(moveresize_client, &x, &y, &w, &h,
305 &lw, &lh, TRUE);
306 if (w == moveresize_client->area.width &&
307 h == moveresize_client->area.height)
308 {
309 return;
310 }
311
312 #ifdef SYNC
313 if (config_resize_redraw && extensions_sync &&
314 moveresize_client->sync_request && moveresize_client->sync_counter)
315 {
316 XEvent ce;
317 XSyncValue val;
318
319 /* are we already waiting for the sync counter to catch up? */
320 if (waiting_for_sync)
321 return;
322
323 /* increment the value we're waiting for */
324 ++moveresize_client->sync_counter_value;
325 XSyncIntToValue(&val, moveresize_client->sync_counter_value);
326
327 /* tell the client what we're waiting for */
328 ce.xclient.type = ClientMessage;
329 ce.xclient.message_type = prop_atoms.wm_protocols;
330 ce.xclient.display = ob_display;
331 ce.xclient.window = moveresize_client->window;
332 ce.xclient.format = 32;
333 ce.xclient.data.l[0] = prop_atoms.net_wm_sync_request;
334 ce.xclient.data.l[1] = event_curtime;
335 ce.xclient.data.l[2] = XSyncValueLow32(val);
336 ce.xclient.data.l[3] = XSyncValueHigh32(val);
337 ce.xclient.data.l[4] = 0l;
338 XSendEvent(ob_display, moveresize_client->window, FALSE,
339 NoEventMask, &ce);
340
341 waiting_for_sync = TRUE;
342
343 ob_main_loop_timeout_remove(ob_main_loop, sync_timeout_func);
344 ob_main_loop_timeout_add(ob_main_loop, G_USEC_PER_SEC * 2,
345 sync_timeout_func,
346 NULL, NULL, NULL);
347 }
348 #endif
349
350 client_configure(moveresize_client, cur_x, cur_y, cur_w, cur_h,
351 TRUE, FALSE, FALSE);
352
353 /* this would be better with a fixed width font ... XXX can do it better
354 if there are 2 text boxes */
355 if (config_resize_popup_show == 2 || /* == "Always" */
356 (config_resize_popup_show == 1 && /* == "Nonpixel" */
357 moveresize_client->size_inc.width > 1 &&
358 moveresize_client->size_inc.height > 1))
359 popup_coords(moveresize_client, "%d x %d",
360 moveresize_client->logical_size.width,
361 moveresize_client->logical_size.height);
362 }
363
364 #ifdef SYNC
365 static gboolean sync_timeout_func(gpointer data)
366 {
367 waiting_for_sync = FALSE; /* we timed out waiting for our sync... */
368 do_resize(); /* ...so let any pending resizes through */
369
370 return FALSE; /* don't repeat */
371 }
372 #endif
373
374 static void calc_resize(gboolean keyboard, gint keydist, gint *dw, gint *dh,
375 ObCorner cor)
376 {
377 gint resist, x, y, lw, lh, ow, oh, nw, nh;
378
379 ow = cur_w;
380 oh = cur_h;
381 /* resist_size_* needs the frame size */
382 nw = ow + *dw +
383 moveresize_client->frame->size.left +
384 moveresize_client->frame->size.right;
385 nh = oh + *dh +
386 moveresize_client->frame->size.top +
387 moveresize_client->frame->size.bottom;
388
389 if (keyboard) resist = keydist - 1; /* resist for one key press */
390 else resist = config_resist_win;
391 resist_size_windows(moveresize_client, resist, &nw, &nh, cor);
392 if (!keyboard) resist = config_resist_edge;
393 resist_size_monitors(moveresize_client, resist, &nw, &nh, cor);
394
395 nw -= moveresize_client->frame->size.left +
396 moveresize_client->frame->size.right;
397 nh -= moveresize_client->frame->size.top +
398 moveresize_client->frame->size.bottom;
399
400 /* see its actual size */
401 x = 0;
402 y = 0;
403 client_try_configure(moveresize_client, &x, &y, &nw, &nh, &lw, &lh, TRUE);
404
405
406 *dw = nw - ow;
407 *dh = nh - oh;
408 }
409
410 static gboolean edge_warp_delay_func(gpointer data)
411 {
412 guint d;
413
414 d = screen_find_desktop(screen_desktop, edge_warp_dir, TRUE, FALSE);
415 if (d != screen_desktop) screen_set_desktop(d, TRUE);
416
417 edge_warp_dir = -1;
418
419 return FALSE; /* don't repeat */
420 }
421
422 static void do_edge_warp(gint x, gint y)
423 {
424 guint i;
425 ObDirection dir;
426
427 if (!config_mouse_screenedgetime) return;
428
429 dir = -1;
430
431 for (i = 0; i < screen_num_monitors; ++i) {
432 Rect *a = screen_physical_area_monitor(i);
433 if (x == RECT_LEFT(*a)) dir = OB_DIRECTION_WEST;
434 if (x == RECT_RIGHT(*a)) dir = OB_DIRECTION_EAST;
435 if (y == RECT_TOP(*a)) dir = OB_DIRECTION_NORTH;
436 if (y == RECT_BOTTOM(*a)) dir = OB_DIRECTION_SOUTH;
437
438 /* try check for xinerama boundaries */
439 if ((x + 1 == RECT_LEFT(*a) || x - 1 == RECT_RIGHT(*a)) &&
440 (dir == OB_DIRECTION_WEST || dir == OB_DIRECTION_EAST))
441 {
442 dir = -1;
443 }
444 if ((y + 1 == RECT_TOP(*a) || y - 1 == RECT_BOTTOM(*a)) &&
445 (dir == OB_DIRECTION_NORTH || dir == OB_DIRECTION_SOUTH))
446 {
447 dir = -1;
448 }
449 g_free(a);
450 }
451
452 if (dir != edge_warp_dir) {
453 if (dir == (ObDirection)-1)
454 cancel_edge_warp();
455 else
456 ob_main_loop_timeout_add(ob_main_loop,
457 config_mouse_screenedgetime * 1000,
458 edge_warp_delay_func,
459 NULL, NULL, NULL);
460 edge_warp_dir = dir;
461 }
462 }
463
464 static void cancel_edge_warp()
465 {
466 ob_main_loop_timeout_remove(ob_main_loop, edge_warp_delay_func);
467 }
468
469 static void move_with_keys(gint keycode, gint state)
470 {
471 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
472 gint opx, px, opy, py;
473 gint dist = 0;
474
475 /* shift means jump to edge */
476 if (state & modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT)) {
477 gint x, y;
478 ObDirection dir;
479
480 if (keycode == ob_keycode(OB_KEY_RIGHT))
481 dir = OB_DIRECTION_EAST;
482 else if (keycode == ob_keycode(OB_KEY_LEFT))
483 dir = OB_DIRECTION_WEST;
484 else if (keycode == ob_keycode(OB_KEY_DOWN))
485 dir = OB_DIRECTION_SOUTH;
486 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
487 dir = OB_DIRECTION_NORTH;
488
489 client_find_move_directional(moveresize_client, dir, &x, &y);
490 dx = x - moveresize_client->area.x;
491 dy = y - moveresize_client->area.y;
492 } else {
493 /* control means fine grained */
494 if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL))
495 dist = 1;
496 else
497 dist = KEY_DIST;
498
499 if (keycode == ob_keycode(OB_KEY_RIGHT))
500 dx = dist;
501 else if (keycode == ob_keycode(OB_KEY_LEFT))
502 dx = -dist;
503 else if (keycode == ob_keycode(OB_KEY_DOWN))
504 dy = dist;
505 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
506 dy = -dist;
507 }
508
509 screen_pointer_pos(&opx, &opy);
510 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
511 /* steal the motion events this causes */
512 XSync(ob_display, FALSE);
513 {
514 XEvent ce;
515 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
516 }
517 screen_pointer_pos(&px, &py);
518
519 cur_x += dx;
520 cur_y += dy;
521 do_move(TRUE, dist);
522
523 /* because the cursor moves even though the window does
524 not nessesarily (resistance), this adjusts where the curor
525 thinks it started so that it keeps up with where the window
526 actually is */
527 start_x += (px - opx) - (cur_x - ox);
528 start_y += (py - opy) - (cur_y - oy);
529 }
530
531 static void resize_with_keys(gint keycode, gint state)
532 {
533 gint dw = 0, dh = 0, pdx = 0, pdy = 0, opx, opy, px, py;
534 gint dist = 0, resist = 0;
535 ObDirection dir;
536 ObCorner cor;
537
538 /* pick the edge if it needs to move */
539 if (keycode == ob_keycode(OB_KEY_RIGHT)) {
540 dir = OB_DIRECTION_EAST;
541 if (key_resize_edge != OB_DIRECTION_WEST &&
542 key_resize_edge != OB_DIRECTION_EAST)
543 {
544 key_resize_edge = OB_DIRECTION_EAST;
545 return;
546 }
547 }
548 if (keycode == ob_keycode(OB_KEY_LEFT)) {
549 dir = OB_DIRECTION_WEST;
550 if (key_resize_edge != OB_DIRECTION_WEST &&
551 key_resize_edge != OB_DIRECTION_EAST)
552 {
553 key_resize_edge = OB_DIRECTION_WEST;
554 return;
555 }
556 }
557 if (keycode == ob_keycode(OB_KEY_UP)) {
558 dir = OB_DIRECTION_NORTH;
559 if (key_resize_edge != OB_DIRECTION_NORTH &&
560 key_resize_edge != OB_DIRECTION_SOUTH)
561 {
562 key_resize_edge = OB_DIRECTION_NORTH;
563 return;
564 }
565 }
566 if (keycode == ob_keycode(OB_KEY_DOWN)) {
567 dir = OB_DIRECTION_SOUTH;
568 if (key_resize_edge != OB_DIRECTION_NORTH &&
569 key_resize_edge != OB_DIRECTION_SOUTH)
570 {
571 key_resize_edge = OB_DIRECTION_SOUTH;
572 return;
573 }
574 }
575
576 /* shift means jump to edge */
577 if (state & modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT)) {
578 gint x, y, w, h;
579
580 if (keycode == ob_keycode(OB_KEY_RIGHT))
581 dir = OB_DIRECTION_EAST;
582 else if (keycode == ob_keycode(OB_KEY_LEFT))
583 dir = OB_DIRECTION_WEST;
584 else if (keycode == ob_keycode(OB_KEY_DOWN))
585 dir = OB_DIRECTION_SOUTH;
586 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
587 dir = OB_DIRECTION_NORTH;
588
589 client_find_resize_directional(moveresize_client, key_resize_edge,
590 key_resize_edge == dir,
591 &x, &y, &w, &h);
592 dw = w - moveresize_client->area.width;
593 dh = h - moveresize_client->area.height;
594 } else {
595 gint distw, disth;
596
597 /* control means fine grained */
598 if (moveresize_client->size_inc.width > 1) {
599 distw = moveresize_client->size_inc.width;
600 resist = 1;
601 }
602 else if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL)) {
603 distw = 1;
604 resist = 1;
605 }
606 else {
607 distw = KEY_DIST;
608 resist = KEY_DIST;
609 }
610 if (moveresize_client->size_inc.height > 1) {
611 disth = moveresize_client->size_inc.height;
612 resist = 1;
613 }
614 else if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL)) {
615 disth = 1;
616 resist = 1;
617 }
618 else {
619 disth = KEY_DIST;
620 resist = KEY_DIST;
621 }
622
623 if (key_resize_edge == OB_DIRECTION_WEST) {
624 if (dir == OB_DIRECTION_WEST)
625 dw = (dist = distw);
626 else
627 dw = -(dist = distw);
628 }
629 else if (key_resize_edge == OB_DIRECTION_EAST) {
630 if (dir == OB_DIRECTION_EAST)
631 dw = (dist = distw);
632 else
633 dw = -(dist = distw);
634 }
635 else if (key_resize_edge == OB_DIRECTION_NORTH) {
636 if (dir == OB_DIRECTION_NORTH)
637 dh = (dist = disth);
638 else
639 dh = -(dist = disth);
640 }
641 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
642 if (dir == OB_DIRECTION_SOUTH)
643 dh = (dist = disth);
644 else
645 dh = -(dist = disth);
646 }
647 }
648
649 /* which corner is locked, for resistance */
650 if (key_resize_edge == OB_DIRECTION_WEST)
651 cor = OB_CORNER_TOPRIGHT;
652 else if (key_resize_edge == OB_DIRECTION_EAST)
653 cor = OB_CORNER_TOPLEFT;
654 else if (key_resize_edge == OB_DIRECTION_NORTH)
655 cor = OB_CORNER_BOTTOMLEFT;
656 else if (key_resize_edge == OB_DIRECTION_SOUTH)
657 cor = OB_CORNER_TOPLEFT;
658
659 calc_resize(TRUE, resist, &dw, &dh, cor);
660 if (key_resize_edge == OB_DIRECTION_WEST)
661 cur_x -= dw;
662 else if (key_resize_edge == OB_DIRECTION_NORTH)
663 cur_y -= dh;
664 cur_w += dw;
665 cur_h += dh;
666
667 /* how to move the pointer to keep up with the change */
668 if (key_resize_edge == OB_DIRECTION_WEST)
669 pdx = -dw;
670 else if (key_resize_edge == OB_DIRECTION_EAST)
671 pdx = dw;
672 else if (key_resize_edge == OB_DIRECTION_NORTH)
673 pdy = -dh;
674 else if (key_resize_edge == OB_DIRECTION_SOUTH)
675 pdy = dh;
676
677 screen_pointer_pos(&opx, &opy);
678 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, pdx, pdy);
679 /* steal the motion events this causes */
680 XSync(ob_display, FALSE);
681 {
682 XEvent ce;
683 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
684 }
685 screen_pointer_pos(&px, &py);
686
687 do_resize();
688
689 /* because the cursor moves even though the window does
690 not nessesarily (resistance), this adjusts where the cursor
691 thinks it started so that it keeps up with where the window
692 actually is */
693 start_x += (px - opx) - dw;
694 start_y += (py - opy) - dh;
695
696 }
697
698 gboolean moveresize_event(XEvent *e)
699 {
700 gboolean used = FALSE;
701
702 if (!moveresize_in_progress) return FALSE;
703
704 if (e->type == ButtonPress) {
705 if (!button) {
706 start_x = e->xbutton.x_root;
707 start_y = e->xbutton.y_root;
708 button = e->xbutton.button; /* this will end it now */
709 }
710 used = e->xbutton.button == button;
711 } else if (e->type == ButtonRelease) {
712 if (!button || e->xbutton.button == button) {
713 moveresize_end(FALSE);
714 used = TRUE;
715 }
716 } else if (e->type == MotionNotify) {
717 if (moving) {
718 cur_x = start_cx + e->xmotion.x_root - start_x;
719 cur_y = start_cy + e->xmotion.y_root - start_y;
720 do_move(FALSE, 0);
721 do_edge_warp(e->xmotion.x_root, e->xmotion.y_root);
722 } else {
723 gint dw, dh;
724
725 if (corner == prop_atoms.net_wm_moveresize_size_topleft) {
726 dw = -(e->xmotion.x_root - start_x);
727 dh = -(e->xmotion.y_root - start_y);
728 lockcorner = OB_CORNER_BOTTOMRIGHT;
729 } else if (corner == prop_atoms.net_wm_moveresize_size_top) {
730 dw = 0;
731 dh = -(e->xmotion.y_root - start_y);
732 lockcorner = OB_CORNER_BOTTOMRIGHT;
733 } else if (corner == prop_atoms.net_wm_moveresize_size_topright) {
734 dw = (e->xmotion.x_root - start_x);
735 dh = -(e->xmotion.y_root - start_y);
736 lockcorner = OB_CORNER_BOTTOMLEFT;
737 } else if (corner == prop_atoms.net_wm_moveresize_size_right) {
738 dw = (e->xmotion.x_root - start_x);
739 dh = 0;
740 lockcorner = OB_CORNER_BOTTOMLEFT;
741 } else if (corner ==
742 prop_atoms.net_wm_moveresize_size_bottomright) {
743 dw = (e->xmotion.x_root - start_x);
744 dh = (e->xmotion.y_root - start_y);
745 lockcorner = OB_CORNER_TOPLEFT;
746 } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) {
747 dw = 0;
748 dh = (e->xmotion.y_root - start_y);
749 lockcorner = OB_CORNER_TOPLEFT;
750 } else if (corner ==
751 prop_atoms.net_wm_moveresize_size_bottomleft) {
752 dw = -(e->xmotion.x_root - start_x);
753 dh = (e->xmotion.y_root - start_y);
754 lockcorner = OB_CORNER_TOPRIGHT;
755 } else if (corner == prop_atoms.net_wm_moveresize_size_left) {
756 dw = -(e->xmotion.x_root - start_x);
757 dh = 0;
758 lockcorner = OB_CORNER_TOPRIGHT;
759 } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
760 dw = (e->xmotion.x_root - start_x);
761 dh = (e->xmotion.y_root - start_y);
762 lockcorner = OB_CORNER_TOPLEFT;
763 } else
764 g_assert_not_reached();
765
766 dw -= cur_w - start_cw;
767 dh -= cur_h - start_ch;
768
769 calc_resize(FALSE, 0, &dw, &dh, lockcorner);
770 cur_w += dw;
771 cur_h += dh;
772
773 if (corner == prop_atoms.net_wm_moveresize_size_topleft ||
774 corner == prop_atoms.net_wm_moveresize_size_left ||
775 corner == prop_atoms.net_wm_moveresize_size_bottomleft)
776 {
777 cur_x -= dw;
778 }
779 if (corner == prop_atoms.net_wm_moveresize_size_topleft ||
780 corner == prop_atoms.net_wm_moveresize_size_top ||
781 corner == prop_atoms.net_wm_moveresize_size_topright)
782 {
783 cur_y -= dh;
784 }
785
786 do_resize();
787 }
788 used = TRUE;
789 } else if (e->type == KeyPress) {
790 if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
791 moveresize_end(TRUE);
792 used = TRUE;
793 } else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
794 moveresize_end(FALSE);
795 used = TRUE;
796 } else if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT) ||
797 e->xkey.keycode == ob_keycode(OB_KEY_LEFT) ||
798 e->xkey.keycode == ob_keycode(OB_KEY_DOWN) ||
799 e->xkey.keycode == ob_keycode(OB_KEY_UP))
800 {
801 if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
802 resize_with_keys(e->xkey.keycode, e->xkey.state);
803 used = TRUE;
804 } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
805 move_with_keys(e->xkey.keycode, e->xkey.state);
806 used = TRUE;
807 }
808 }
809 }
810 #ifdef SYNC
811 else if (e->type == extensions_sync_event_basep + XSyncAlarmNotify)
812 {
813 waiting_for_sync = FALSE; /* we got our sync... */
814 do_resize(); /* ...so try resize if there is more change pending */
815 used = TRUE;
816 }
817 #endif
818 return used;
819 }
This page took 0.070813 seconds and 5 git commands to generate.