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