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