]> Dogcows Code - chaz/openbox/blob - openbox/moveresize.c
fix XSYNCronization of resizes (especially with two monitors).
[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 "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 "event.h"
31 #include "debug.h"
32 #include "obrender/render.h"
33 #include "obrender/theme.h"
34 #include "obt/display.h"
35 #include "obt/xqueue.h"
36 #include "obt/prop.h"
37 #include "obt/keyboard.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 #define SYNC_TIMEOUTS 4
45
46 gboolean moveresize_in_progress = FALSE;
47 ObClient *moveresize_client = NULL;
48 #ifdef SYNC
49 XSyncAlarm moveresize_alarm = None;
50 #endif
51
52 static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */
53
54 static gint start_x, start_y, start_cx, start_cy, start_cw, start_ch;
55 static gint cur_x, cur_y, cur_w, cur_h;
56 static guint button;
57 static guint32 corner;
58 static ObDirection edge_warp_dir = -1;
59 static gboolean edge_warp_odd = FALSE;
60 static ObDirection key_resize_edge = -1;
61 #ifdef SYNC
62 static guint waiting_for_sync;
63 #endif
64
65 static ObPopup *popup = NULL;
66
67 static void do_move(gboolean keyboard, gint keydist);
68 static void do_resize(void);
69 static void do_edge_warp(gint x, gint y);
70 static void cancel_edge_warp();
71 #ifdef SYNC
72 static gboolean sync_timeout_func(gpointer data);
73 #endif
74
75 static void client_dest(ObClient *client, gpointer data)
76 {
77 if (moveresize_client == client)
78 moveresize_end(TRUE);
79 }
80
81 void moveresize_startup(gboolean reconfig)
82 {
83 popup = popup_new();
84 popup_set_text_align(popup, RR_JUSTIFY_CENTER);
85
86 if (!reconfig)
87 client_add_destroy_notify(client_dest, NULL);
88 }
89
90 void moveresize_shutdown(gboolean reconfig)
91 {
92 if (!reconfig) {
93 if (moveresize_in_progress)
94 moveresize_end(FALSE);
95 client_remove_destroy_notify(client_dest);
96 }
97
98 popup_free(popup);
99 popup = NULL;
100 }
101
102 static void popup_coords(ObClient *c, const gchar *format, gint a, gint b)
103 {
104 gchar *text;
105
106 text = g_strdup_printf(format, a, b);
107 if (config_resize_popup_pos == OB_RESIZE_POS_TOP)
108 popup_position(popup, SouthGravity,
109 c->frame->area.x
110 + c->frame->area.width/2,
111 c->frame->area.y - ob_rr_theme->fbwidth);
112 else if (config_resize_popup_pos == OB_RESIZE_POS_CENTER)
113 popup_position(popup, CenterGravity,
114 c->frame->area.x + c->frame->area.width / 2,
115 c->frame->area.y + c->frame->area.height / 2);
116 else /* Fixed */ {
117 const Rect *area = screen_physical_area_active();
118 gint gravity, x, y;
119
120 x = config_resize_popup_fixed.x.pos;
121 if (config_resize_popup_fixed.x.center)
122 x = area->x + area->width/2;
123 else if (config_resize_popup_fixed.x.opposite)
124 x = RECT_RIGHT(*area) - x;
125 else
126 x = area->x + x;
127
128 y = config_resize_popup_fixed.y.pos;
129 if (config_resize_popup_fixed.y.center)
130 y = area->y + area->height/2;
131 else if (config_resize_popup_fixed.y.opposite)
132 y = RECT_RIGHT(*area) - y;
133 else
134 y = area->y + y;
135
136 if (config_resize_popup_fixed.x.center) {
137 if (config_resize_popup_fixed.y.center)
138 gravity = CenterGravity;
139 else if (config_resize_popup_fixed.y.opposite)
140 gravity = SouthGravity;
141 else
142 gravity = NorthGravity;
143 }
144 else if (config_resize_popup_fixed.x.opposite) {
145 if (config_resize_popup_fixed.y.center)
146 gravity = EastGravity;
147 else if (config_resize_popup_fixed.y.opposite)
148 gravity = SouthEastGravity;
149 else
150 gravity = NorthEastGravity;
151 }
152 else {
153 if (config_resize_popup_fixed.y.center)
154 gravity = WestGravity;
155 else if (config_resize_popup_fixed.y.opposite)
156 gravity = SouthWestGravity;
157 else
158 gravity = NorthWestGravity;
159 }
160
161 popup_position(popup, gravity, x, y);
162 }
163 popup_show(popup, text);
164 g_free(text);
165 }
166
167 void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
168 {
169 ObCursor cur;
170 gboolean mv = (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE) ||
171 cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD));
172 gint up = 1;
173 gint left = 1;
174
175 if (moveresize_in_progress || !c->frame->visible ||
176 !(mv ?
177 (c->functions & OB_CLIENT_FUNC_MOVE) :
178 (c->functions & OB_CLIENT_FUNC_RESIZE)))
179 return;
180
181 if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT)) {
182 cur = OB_CURSOR_NORTHWEST;
183 up = left = -1;
184 }
185 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP)) {
186 cur = OB_CURSOR_NORTH;
187 up = -1;
188 }
189 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT)) {
190 cur = OB_CURSOR_NORTHEAST;
191 up = -1;
192 }
193 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT))
194 cur = OB_CURSOR_EAST;
195 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT))
196 cur = OB_CURSOR_SOUTHEAST;
197 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM))
198 cur = OB_CURSOR_SOUTH;
199 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT)) {
200 cur = OB_CURSOR_SOUTHWEST;
201 left = -1;
202 }
203 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT)) {
204 cur = OB_CURSOR_WEST;
205 left = -1;
206 }
207 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD))
208 cur = OB_CURSOR_SOUTHEAST;
209 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE))
210 cur = OB_CURSOR_MOVE;
211 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD))
212 cur = OB_CURSOR_MOVE;
213 else
214 g_assert_not_reached();
215
216 /* keep the pointer bounded to the screen for move/resize */
217 if (!grab_pointer(FALSE, TRUE, cur))
218 return;
219 if (!grab_keyboard()) {
220 ungrab_pointer();
221 return;
222 }
223
224 frame_end_iconify_animation(c->frame);
225
226 moving = mv;
227 moveresize_client = c;
228 start_cx = c->area.x;
229 start_cy = c->area.y;
230 start_cw = c->area.width;
231 start_ch = c->area.height;
232 /* these adjustments for the size_inc make resizing a terminal more
233 friendly. you essentially start the resize in the middle of the
234 increment instead of at 0, so you have to move half an increment
235 either way instead of a full increment one and 1 px the other. */
236 start_x = x - (mv ? 0 : left * c->size_inc.width / 2);
237 start_y = y - (mv ? 0 : up * c->size_inc.height / 2);
238 corner = cnr;
239 button = b;
240 key_resize_edge = -1;
241
242 /*
243 have to change start_cx and start_cy if going to do this..
244 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
245 corner == prop_atoms.net_wm_moveresize_size_keyboard)
246 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
247 c->area.width / 2, c->area.height / 2);
248 */
249
250 cur_x = start_cx;
251 cur_y = start_cy;
252 cur_w = start_cw;
253 cur_h = start_ch;
254
255 moveresize_in_progress = TRUE;
256
257 #ifdef SYNC
258 if (config_resize_redraw && !moving && obt_display_extension_sync &&
259 moveresize_client->sync_request && moveresize_client->sync_counter &&
260 !moveresize_client->not_responding)
261 {
262 /* Initialize values for the resize syncing, and create an alarm for
263 the client's xsync counter */
264
265 XSyncValue val;
266 XSyncAlarmAttributes aa;
267
268 /* set the counter to an initial value */
269 XSyncIntToValue(&val, 0);
270 XSyncSetCounter(obt_display, moveresize_client->sync_counter, val);
271
272 /* this will be incremented when we tell the client what we're
273 looking for */
274 moveresize_client->sync_counter_value = 0;
275
276 /* the next sequence we're waiting for with the alarm */
277 XSyncIntToValue(&val, 1);
278
279 /* set an alarm on the counter */
280 aa.trigger.counter = moveresize_client->sync_counter;
281 aa.trigger.wait_value = val;
282 aa.trigger.value_type = XSyncAbsolute;
283 aa.trigger.test_type = XSyncPositiveTransition;
284 aa.events = True;
285 XSyncIntToValue(&aa.delta, 1);
286 moveresize_alarm = XSyncCreateAlarm(obt_display,
287 XSyncCACounter |
288 XSyncCAValue |
289 XSyncCAValueType |
290 XSyncCATestType |
291 XSyncCADelta |
292 XSyncCAEvents,
293 &aa);
294
295 waiting_for_sync = 0;
296 }
297 #endif
298 }
299
300 void moveresize_end(gboolean cancel)
301 {
302 ungrab_keyboard();
303 ungrab_pointer();
304
305 popup_hide(popup);
306
307 if (!moving) {
308 #ifdef SYNC
309 /* turn off the alarm */
310 if (moveresize_alarm != None) {
311 XSyncDestroyAlarm(obt_display, moveresize_alarm);
312 moveresize_alarm = None;
313 }
314
315 obt_main_loop_timeout_remove(ob_main_loop, sync_timeout_func);
316 #endif
317 }
318
319 /* don't use client_move() here, use the same width/height as
320 we've been using during the move, otherwise we get different results
321 when moving maximized windows between monitors of different sizes !
322 */
323 client_configure(moveresize_client,
324 (cancel ? start_cx : cur_x),
325 (cancel ? start_cy : cur_y),
326 (cancel ? start_cw : cur_w),
327 (cancel ? start_ch : cur_h),
328 TRUE, TRUE, FALSE);
329
330 /* dont edge warp after its ended */
331 cancel_edge_warp();
332
333 moveresize_in_progress = FALSE;
334 moveresize_client = NULL;
335 }
336
337 static void do_move(gboolean keyboard, gint keydist)
338 {
339 gint resist;
340
341 if (keyboard) resist = keydist - 1; /* resist for one key press */
342 else resist = config_resist_win;
343 resist_move_windows(moveresize_client, resist, &cur_x, &cur_y);
344 if (!keyboard) resist = config_resist_edge;
345 resist_move_monitors(moveresize_client, resist, &cur_x, &cur_y);
346
347 client_configure(moveresize_client, cur_x, cur_y, cur_w, cur_h,
348 TRUE, FALSE, FALSE);
349 if (config_resize_popup_show == 2) /* == "Always" */
350 popup_coords(moveresize_client, "%d x %d",
351 moveresize_client->frame->area.x,
352 moveresize_client->frame->area.y);
353 }
354
355 static void do_resize(void)
356 {
357 gint x, y, w, h, lw, lh;
358
359 /* see if it is actually going to resize
360 USE cur_x AND cur_y HERE ! Otherwise the try_configure won't know
361 what struts to use !!
362 */
363 x = cur_x;
364 y = cur_y;
365 w = cur_w;
366 h = cur_h;
367 client_try_configure(moveresize_client, &x, &y, &w, &h,
368 &lw, &lh, TRUE);
369 if (!(w == moveresize_client->area.width &&
370 h == moveresize_client->area.height) &&
371 /* if waiting_for_sync == 0, then we aren't waiting.
372 if it is > SYNC_TIMEOUTS, then we have timed out
373 that many times already, so forget about waiting more */
374 (waiting_for_sync == 0 || waiting_for_sync > SYNC_TIMEOUTS))
375 {
376 #ifdef SYNC
377 if (config_resize_redraw && obt_display_extension_sync &&
378 /* don't send another sync when one is pending */
379 waiting_for_sync == 0 &&
380 moveresize_client->sync_request &&
381 moveresize_client->sync_counter &&
382 !moveresize_client->not_responding)
383 {
384 XEvent ce;
385 XSyncValue val;
386
387 /* increment the value we're waiting for */
388 ++moveresize_client->sync_counter_value;
389 XSyncIntToValue(&val, moveresize_client->sync_counter_value);
390
391 /* tell the client what we're waiting for */
392 ce.xclient.type = ClientMessage;
393 ce.xclient.message_type = OBT_PROP_ATOM(WM_PROTOCOLS);
394 ce.xclient.display = obt_display;
395 ce.xclient.window = moveresize_client->window;
396 ce.xclient.format = 32;
397 ce.xclient.data.l[0] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST);
398 ce.xclient.data.l[1] = event_time();
399 ce.xclient.data.l[2] = XSyncValueLow32(val);
400 ce.xclient.data.l[3] = XSyncValueHigh32(val);
401 ce.xclient.data.l[4] = 0l;
402 XSendEvent(obt_display, moveresize_client->window, FALSE,
403 NoEventMask, &ce);
404
405 waiting_for_sync = 1;
406
407 obt_main_loop_timeout_remove(ob_main_loop, sync_timeout_func);
408 obt_main_loop_timeout_add(ob_main_loop, G_USEC_PER_SEC * 2,
409 sync_timeout_func,
410 NULL, NULL, NULL);
411 }
412 #endif
413
414 /* force a ConfigureNotify, it is part of the spec for SYNC resizing
415 and MUST follow the sync counter notification */
416 client_configure(moveresize_client, cur_x, cur_y, cur_w, cur_h,
417 TRUE, FALSE, TRUE);
418 }
419
420 /* this would be better with a fixed width font ... XXX can do it better
421 if there are 2 text boxes */
422 if (config_resize_popup_show == 2 || /* == "Always" */
423 (config_resize_popup_show == 1 && /* == "Nonpixel" */
424 moveresize_client->size_inc.width > 1 &&
425 moveresize_client->size_inc.height > 1))
426 popup_coords(moveresize_client, "%d x %d", lw, lh);
427 }
428
429 #ifdef SYNC
430 static gboolean sync_timeout_func(gpointer data)
431 {
432 ++waiting_for_sync; /* we timed out waiting for our sync... */
433 do_resize(); /* ...so let any pending resizes through */
434
435 if (waiting_for_sync > SYNC_TIMEOUTS)
436 return FALSE; /* don't repeat */
437 else
438 return TRUE; /* keep waiting */
439 }
440 #endif
441
442 static void calc_resize(gboolean keyboard, gint keydist, gint *dw, gint *dh,
443 ObDirection dir)
444 {
445 gint resist, x = 0, y = 0, lw, lh, ow, oh, nw, nh;
446 gint trydw, trydh;
447
448 ow = cur_w;
449 oh = cur_h;
450 nw = ow + *dw;
451 nh = oh + *dh;
452
453 if (!keyboard &&
454 (moveresize_client->max_ratio || moveresize_client->min_ratio))
455 {
456 switch (dir) {
457 case OB_DIRECTION_NORTH:
458 case OB_DIRECTION_SOUTH:
459 /* resize the width based on the height */
460 if (moveresize_client->min_ratio) {
461 if (nh * moveresize_client->min_ratio > nw)
462 nw = (gint)(nh * moveresize_client->min_ratio);
463 }
464 if (moveresize_client->max_ratio) {
465 if (nh * moveresize_client->max_ratio < nw)
466 nw = (gint)(nh * moveresize_client->max_ratio);
467 }
468 break;
469 default:
470 /* resize the height based on the width */
471 if (moveresize_client->min_ratio) {
472 if (nh * moveresize_client->min_ratio > nw)
473 nh = (gint)(nw / moveresize_client->min_ratio);
474 }
475 if (moveresize_client->max_ratio) {
476 if (nh * moveresize_client->max_ratio < nw)
477 nh = (gint)(nw / moveresize_client->max_ratio);
478 }
479 break;
480 }
481
482 /* see its actual size (apply aspect ratios) */
483 client_try_configure(moveresize_client, &x, &y, &nw, &nh, &lw, &lh,
484 TRUE);
485 trydw = nw - ow;
486 trydh = nh - oh;
487 }
488
489 /* resist_size_* needs the frame size */
490 nw += moveresize_client->frame->size.left +
491 moveresize_client->frame->size.right;
492 nh += moveresize_client->frame->size.top +
493 moveresize_client->frame->size.bottom;
494
495 if (keyboard) resist = keydist - 1; /* resist for one key press */
496 else resist = config_resist_win;
497 resist_size_windows(moveresize_client, resist, &nw, &nh, dir);
498 if (!keyboard) resist = config_resist_edge;
499 resist_size_monitors(moveresize_client, resist, &nw, &nh, dir);
500
501 nw -= moveresize_client->frame->size.left +
502 moveresize_client->frame->size.right;
503 nh -= moveresize_client->frame->size.top +
504 moveresize_client->frame->size.bottom;
505
506 *dw = nw - ow;
507 *dh = nh - oh;
508
509 /* take aspect ratios into account for resistance */
510 if (!keyboard &&
511 (moveresize_client->max_ratio || moveresize_client->min_ratio))
512 {
513 if (*dh != trydh) { /* got resisted */
514 /* resize the width based on the height */
515 if (moveresize_client->min_ratio) {
516 if (nh * moveresize_client->min_ratio > nw)
517 nw = (gint)(nh * moveresize_client->min_ratio);
518 }
519 if (moveresize_client->max_ratio) {
520 if (nh * moveresize_client->max_ratio < nw)
521 nw = (gint)(nh * moveresize_client->max_ratio);
522 }
523 }
524 if (*dw != trydw) { /* got resisted */
525 /* resize the height based on the width */
526 if (moveresize_client->min_ratio) {
527 if (nh * moveresize_client->min_ratio > nw)
528 nh = (gint)(nw / moveresize_client->min_ratio);
529 }
530 if (moveresize_client->max_ratio) {
531 if (nh * moveresize_client->max_ratio < nw)
532 nh = (gint)(nw / moveresize_client->max_ratio);
533 }
534 }
535 }
536
537 /* make sure it's all valid */
538 client_try_configure(moveresize_client, &x, &y, &nw, &nh, &lw, &lh, TRUE);
539
540 *dw = nw - ow;
541 *dh = nh - oh;
542 }
543
544 static void edge_warp_move_ptr(void)
545 {
546 gint x, y;
547 const Rect* a;
548
549 screen_pointer_pos(&x, &y);
550 a = screen_physical_area_all_monitors();
551
552 switch (edge_warp_dir) {
553 case OB_DIRECTION_NORTH:
554 y = a->height - 1;
555 break;
556 case OB_DIRECTION_EAST:
557 x = a->x;
558 break;
559 case OB_DIRECTION_SOUTH:
560 y = a->y;
561 break;
562 case OB_DIRECTION_WEST:
563 x = a->width - 1;
564 break;
565 default:
566 g_assert_not_reached();
567 }
568
569 XWarpPointer(obt_display, 0, obt_root(ob_screen), 0, 0, 0, 0, x, y);
570 }
571
572 static gboolean edge_warp_delay_func(gpointer data)
573 {
574 guint d;
575
576 /* only fire every second time. so it's fast the first time, but slower
577 after that */
578 if (edge_warp_odd) {
579 d = screen_find_desktop(screen_desktop, edge_warp_dir, TRUE, FALSE);
580 if (d != screen_desktop) {
581 if (config_mouse_screenedgewarp) edge_warp_move_ptr();
582 screen_set_desktop(d, TRUE);
583 }
584 }
585 edge_warp_odd = !edge_warp_odd;
586
587 return TRUE; /* do repeat ! */
588 }
589
590 static void do_edge_warp(gint x, gint y)
591 {
592 guint i;
593 ObDirection dir;
594
595 if (!config_mouse_screenedgetime) return;
596
597 dir = -1;
598
599 for (i = 0; i < screen_num_monitors; ++i) {
600 const Rect *a = screen_physical_area_monitor(i);
601 if (x == RECT_LEFT(*a)) dir = OB_DIRECTION_WEST;
602 if (x == RECT_RIGHT(*a)) dir = OB_DIRECTION_EAST;
603 if (y == RECT_TOP(*a)) dir = OB_DIRECTION_NORTH;
604 if (y == RECT_BOTTOM(*a)) dir = OB_DIRECTION_SOUTH;
605
606 /* try check for xinerama boundaries */
607 if ((x + 1 == RECT_LEFT(*a) || x - 1 == RECT_RIGHT(*a)) &&
608 (dir == OB_DIRECTION_WEST || dir == OB_DIRECTION_EAST))
609 {
610 dir = -1;
611 }
612 if ((y + 1 == RECT_TOP(*a) || y - 1 == RECT_BOTTOM(*a)) &&
613 (dir == OB_DIRECTION_NORTH || dir == OB_DIRECTION_SOUTH))
614 {
615 dir = -1;
616 }
617 }
618
619 if (dir != edge_warp_dir) {
620 cancel_edge_warp();
621 if (dir != (ObDirection)-1) {
622 edge_warp_odd = TRUE; /* switch on the first timeout */
623 obt_main_loop_timeout_add(ob_main_loop,
624 config_mouse_screenedgetime * 1000,
625 edge_warp_delay_func,
626 NULL, NULL, NULL);
627 }
628 edge_warp_dir = dir;
629 }
630 }
631
632 static void cancel_edge_warp(void)
633 {
634 obt_main_loop_timeout_remove(ob_main_loop, edge_warp_delay_func);
635 }
636
637 static void move_with_keys(KeySym sym, guint state)
638 {
639 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
640 gint opx, px, opy, py;
641 gint dist = 0;
642
643 /* shift means jump to edge */
644 if (state & obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT))
645 {
646 gint x, y;
647 ObDirection dir;
648
649 if (sym == XK_Right)
650 dir = OB_DIRECTION_EAST;
651 else if (sym == XK_Left)
652 dir = OB_DIRECTION_WEST;
653 else if (sym == XK_Down)
654 dir = OB_DIRECTION_SOUTH;
655 else /* sym == XK_Up */
656 dir = OB_DIRECTION_NORTH;
657
658 client_find_move_directional(moveresize_client, dir, &x, &y);
659 dx = x - moveresize_client->area.x;
660 dy = y - moveresize_client->area.y;
661 } else {
662 /* control means fine grained */
663 if (state &
664 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL))
665 {
666 dist = 1;
667 }
668 else
669 dist = KEY_DIST;
670
671 if (sym == XK_Right)
672 dx = dist;
673 else if (sym == XK_Left)
674 dx = -dist;
675 else if (sym == XK_Down)
676 dy = dist;
677 else /* if (sym == XK_Up) */
678 dy = -dist;
679 }
680
681 screen_pointer_pos(&opx, &opy);
682 XWarpPointer(obt_display, None, None, 0, 0, 0, 0, dx, dy);
683 /* steal the motion events this causes */
684 XSync(obt_display, FALSE);
685 {
686 XEvent ce;
687 while (xqueue_remove_local(&ce, xqueue_match_type,
688 GINT_TO_POINTER(MotionNotify)));
689 }
690 screen_pointer_pos(&px, &py);
691
692 cur_x += dx;
693 cur_y += dy;
694 do_move(TRUE, dist);
695
696 /* because the cursor moves even though the window does
697 not nessesarily (resistance), this adjusts where the curor
698 thinks it started so that it keeps up with where the window
699 actually is */
700 start_x += (px - opx) - (cur_x - ox);
701 start_y += (py - opy) - (cur_y - oy);
702 }
703
704 static void resize_with_keys(KeySym sym, guint state)
705 {
706 gint dw = 0, dh = 0, pdx = 0, pdy = 0, opx, opy, px, py;
707 gint resist = 0;
708 ObDirection dir;
709
710 /* pick the edge if it needs to move */
711 if (sym == XK_Right) {
712 dir = OB_DIRECTION_EAST;
713 if (key_resize_edge != OB_DIRECTION_WEST &&
714 key_resize_edge != OB_DIRECTION_EAST)
715 {
716 key_resize_edge = OB_DIRECTION_EAST;
717 return;
718 }
719 } else if (sym == XK_Left) {
720 dir = OB_DIRECTION_WEST;
721 if (key_resize_edge != OB_DIRECTION_WEST &&
722 key_resize_edge != OB_DIRECTION_EAST)
723 {
724 key_resize_edge = OB_DIRECTION_WEST;
725 return;
726 }
727 } else if (sym == XK_Up) {
728 dir = OB_DIRECTION_NORTH;
729 if (key_resize_edge != OB_DIRECTION_NORTH &&
730 key_resize_edge != OB_DIRECTION_SOUTH)
731 {
732 key_resize_edge = OB_DIRECTION_NORTH;
733 return;
734 }
735 } else /* if (sym == XK_Down) */ {
736 dir = OB_DIRECTION_SOUTH;
737 if (key_resize_edge != OB_DIRECTION_NORTH &&
738 key_resize_edge != OB_DIRECTION_SOUTH)
739 {
740 key_resize_edge = OB_DIRECTION_SOUTH;
741 return;
742 }
743 }
744
745 /* shift means jump to edge */
746 if (state & obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT))
747 {
748 gint x, y, w, h;
749
750 if (sym == XK_Right)
751 dir = OB_DIRECTION_EAST;
752 else if (sym == XK_Left)
753 dir = OB_DIRECTION_WEST;
754 else if (sym == XK_Down)
755 dir = OB_DIRECTION_SOUTH;
756 else /* if (sym == XK_Up)) */
757 dir = OB_DIRECTION_NORTH;
758
759 client_find_resize_directional(moveresize_client, key_resize_edge,
760 key_resize_edge == dir,
761 &x, &y, &w, &h);
762 dw = w - moveresize_client->area.width;
763 dh = h - moveresize_client->area.height;
764 } else {
765 gint distw, disth;
766
767 /* control means fine grained */
768 if (moveresize_client->size_inc.width > 1) {
769 distw = moveresize_client->size_inc.width;
770 resist = 1;
771 }
772 else if (state &
773 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL))
774 {
775 distw = 1;
776 resist = 1;
777 }
778 else {
779 distw = KEY_DIST;
780 resist = KEY_DIST;
781 }
782 if (moveresize_client->size_inc.height > 1) {
783 disth = moveresize_client->size_inc.height;
784 resist = 1;
785 }
786 else if (state &
787 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL))
788 {
789 disth = 1;
790 resist = 1;
791 }
792 else {
793 disth = KEY_DIST;
794 resist = KEY_DIST;
795 }
796
797 if (key_resize_edge == OB_DIRECTION_WEST) {
798 if (dir == OB_DIRECTION_WEST)
799 dw = distw;
800 else
801 dw = -distw;
802 }
803 else if (key_resize_edge == OB_DIRECTION_EAST) {
804 if (dir == OB_DIRECTION_EAST)
805 dw = distw;
806 else
807 dw = -distw;
808 }
809 else if (key_resize_edge == OB_DIRECTION_NORTH) {
810 if (dir == OB_DIRECTION_NORTH)
811 dh = disth;
812 else
813 dh = -disth;
814 }
815 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
816 if (dir == OB_DIRECTION_SOUTH)
817 dh = disth;
818 else
819 dh = -disth;
820 }
821 }
822
823 calc_resize(TRUE, resist, &dw, &dh, dir);
824 if (key_resize_edge == OB_DIRECTION_WEST)
825 cur_x -= dw;
826 else if (key_resize_edge == OB_DIRECTION_NORTH)
827 cur_y -= dh;
828 cur_w += dw;
829 cur_h += dh;
830
831 /* how to move the pointer to keep up with the change */
832 if (key_resize_edge == OB_DIRECTION_WEST)
833 pdx = -dw;
834 else if (key_resize_edge == OB_DIRECTION_EAST)
835 pdx = dw;
836 else if (key_resize_edge == OB_DIRECTION_NORTH)
837 pdy = -dh;
838 else if (key_resize_edge == OB_DIRECTION_SOUTH)
839 pdy = dh;
840
841 screen_pointer_pos(&opx, &opy);
842 XWarpPointer(obt_display, None, None, 0, 0, 0, 0, pdx, pdy);
843 /* steal the motion events this causes */
844 XSync(obt_display, FALSE);
845 {
846 XEvent ce;
847 while (xqueue_remove_local(&ce, xqueue_match_type,
848 GINT_TO_POINTER(MotionNotify)));
849 }
850 screen_pointer_pos(&px, &py);
851
852 do_resize();
853
854 /* because the cursor moves even though the window does
855 not nessesarily (resistance), this adjusts where the cursor
856 thinks it started so that it keeps up with where the window
857 actually is */
858 start_x += (px - opx) - dw;
859 start_y += (py - opy) - dh;
860
861 }
862
863 gboolean moveresize_event(XEvent *e)
864 {
865 gboolean used = FALSE;
866
867 if (!moveresize_in_progress) return FALSE;
868
869 if (e->type == ButtonPress) {
870 if (!button) {
871 start_x = e->xbutton.x_root;
872 start_y = e->xbutton.y_root;
873 button = e->xbutton.button; /* this will end it now */
874 }
875 used = e->xbutton.button == button;
876 } else if (e->type == ButtonRelease) {
877 if (!button || e->xbutton.button == button) {
878 moveresize_end(FALSE);
879 used = TRUE;
880 }
881 } else if (e->type == MotionNotify) {
882 if (moving) {
883 cur_x = start_cx + e->xmotion.x_root - start_x;
884 cur_y = start_cy + e->xmotion.y_root - start_y;
885 do_move(FALSE, 0);
886 do_edge_warp(e->xmotion.x_root, e->xmotion.y_root);
887 } else {
888 gint dw, dh;
889 ObDirection dir;
890
891 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT)) {
892 dw = -(e->xmotion.x_root - start_x);
893 dh = -(e->xmotion.y_root - start_y);
894 dir = OB_DIRECTION_NORTHWEST;
895 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP)) {
896 dw = 0;
897 dh = -(e->xmotion.y_root - start_y);
898 dir = OB_DIRECTION_NORTH;
899 } else if (corner ==
900 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT)) {
901 dw = (e->xmotion.x_root - start_x);
902 dh = -(e->xmotion.y_root - start_y);
903 dir = OB_DIRECTION_NORTHEAST;
904 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT)) {
905 dw = (e->xmotion.x_root - start_x);
906 dh = 0;
907 dir = OB_DIRECTION_EAST;
908 } else if (corner ==
909 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT)) {
910 dw = (e->xmotion.x_root - start_x);
911 dh = (e->xmotion.y_root - start_y);
912 dir = OB_DIRECTION_SOUTHEAST;
913 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM))
914 {
915 dw = 0;
916 dh = (e->xmotion.y_root - start_y);
917 dir = OB_DIRECTION_SOUTH;
918 } else if (corner ==
919 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT)) {
920 dw = -(e->xmotion.x_root - start_x);
921 dh = (e->xmotion.y_root - start_y);
922 dir = OB_DIRECTION_SOUTHWEST;
923 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT)) {
924 dw = -(e->xmotion.x_root - start_x);
925 dh = 0;
926 dir = OB_DIRECTION_WEST;
927 } else if (corner ==
928 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD)) {
929 dw = (e->xmotion.x_root - start_x);
930 dh = (e->xmotion.y_root - start_y);
931 dir = OB_DIRECTION_SOUTHEAST;
932 } else
933 g_assert_not_reached();
934
935 dw -= cur_w - start_cw;
936 dh -= cur_h - start_ch;
937
938 calc_resize(FALSE, 0, &dw, &dh, dir);
939 cur_w += dw;
940 cur_h += dh;
941
942 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT) ||
943 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT) ||
944 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT))
945 {
946 cur_x -= dw;
947 }
948 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT) ||
949 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP) ||
950 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT))
951 {
952 cur_y -= dh;
953 }
954
955 do_resize();
956 }
957 used = TRUE;
958 } else if (e->type == KeyPress) {
959 KeySym sym = obt_keyboard_keypress_to_keysym(e);
960
961 if (sym == XK_Escape) {
962 moveresize_end(TRUE);
963 used = TRUE;
964 } else if (sym == XK_Return || sym == XK_KP_Enter) {
965 moveresize_end(FALSE);
966 used = TRUE;
967 } else if (sym == XK_Right || sym == XK_Left ||
968 sym == XK_Up || sym == XK_Down)
969 {
970 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD)) {
971 resize_with_keys(sym, e->xkey.state);
972 used = TRUE;
973 } else if (corner ==
974 OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD))
975 {
976 move_with_keys(sym, e->xkey.state);
977 used = TRUE;
978 }
979 }
980 }
981 #ifdef SYNC
982 else if (e->type == obt_display_extension_sync_basep + XSyncAlarmNotify)
983 {
984 waiting_for_sync = 0; /* we got our sync... */
985 do_resize(); /* ...so try resize if there is more change pending */
986 used = TRUE;
987 }
988 #endif
989 return used;
990 }
This page took 0.087854 seconds and 5 git commands to generate.