]> Dogcows Code - chaz/openbox/blob - openbox/moveresize.c
Merge branch 'backport' into work
[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 "render/render.h"
33 #include "render/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_edge_warp(gint x, gint y);
66 static void cancel_edge_warp();
67 #ifdef SYNC
68 static gboolean sync_timeout_func(gpointer data);
69 #endif
70
71 static void client_dest(ObClient *client, gpointer data)
72 {
73 if (moveresize_client == client)
74 moveresize_end(TRUE);
75 }
76
77 void moveresize_startup(gboolean reconfig)
78 {
79 popup = popup_new();
80 popup_set_text_align(popup, RR_JUSTIFY_CENTER);
81
82 if (!reconfig)
83 client_add_destroy_notify(client_dest, NULL);
84 }
85
86 void moveresize_shutdown(gboolean reconfig)
87 {
88 if (!reconfig) {
89 if (moveresize_in_progress)
90 moveresize_end(FALSE);
91 client_remove_destroy_notify(client_dest);
92 }
93
94 popup_free(popup);
95 popup = NULL;
96 }
97
98 static void popup_coords(ObClient *c, const gchar *format, gint a, gint b)
99 {
100 gchar *text;
101
102 text = g_strdup_printf(format, a, b);
103 if (config_resize_popup_pos == OB_RESIZE_POS_TOP)
104 popup_position(popup, SouthGravity,
105 c->frame->area.x
106 + c->frame->area.width/2,
107 c->frame->area.y - ob_rr_theme->fbwidth);
108 else if (config_resize_popup_pos == OB_RESIZE_POS_CENTER)
109 popup_position(popup, CenterGravity,
110 c->frame->area.x + c->frame->size.left +
111 c->area.width / 2,
112 c->frame->area.y + c->frame->size.top +
113 c->area.height / 2);
114 else /* Fixed */ {
115 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 g_free(area);
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 = FALSE;
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 client_move(moveresize_client,
309 (cancel ? start_cx : cur_x),
310 (cancel ? start_cy : cur_y));
311 } else {
312 #ifdef SYNC
313 /* turn off the alarm */
314 if (moveresize_alarm != None) {
315 XSyncDestroyAlarm(obt_display, moveresize_alarm);
316 moveresize_alarm = None;
317 }
318
319 obt_main_loop_timeout_remove(ob_main_loop, sync_timeout_func);
320 #endif
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
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
356 static void do_resize(void)
357 {
358 gint x, y, w, h, lw, lh;
359
360 /* see if it is actually going to resize */
361 x = 0;
362 y = 0;
363 w = cur_w;
364 h = cur_h;
365 client_try_configure(moveresize_client, &x, &y, &w, &h,
366 &lw, &lh, TRUE);
367 if (w == moveresize_client->area.width &&
368 h == moveresize_client->area.height)
369 {
370 return;
371 }
372
373 #ifdef SYNC
374 if (config_resize_redraw && obt_display_extension_sync &&
375 moveresize_client->sync_request && moveresize_client->sync_counter &&
376 !moveresize_client->not_responding)
377 {
378 XEvent ce;
379 XSyncValue val;
380
381 /* are we already waiting for the sync counter to catch up? */
382 if (waiting_for_sync)
383 return;
384
385 /* increment the value we're waiting for */
386 ++moveresize_client->sync_counter_value;
387 XSyncIntToValue(&val, moveresize_client->sync_counter_value);
388
389 /* tell the client what we're waiting for */
390 ce.xclient.type = ClientMessage;
391 ce.xclient.message_type = OBT_PROP_ATOM(WM_PROTOCOLS);
392 ce.xclient.display = obt_display;
393 ce.xclient.window = moveresize_client->window;
394 ce.xclient.format = 32;
395 ce.xclient.data.l[0] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST);
396 ce.xclient.data.l[1] = event_curtime;
397 ce.xclient.data.l[2] = XSyncValueLow32(val);
398 ce.xclient.data.l[3] = XSyncValueHigh32(val);
399 ce.xclient.data.l[4] = 0l;
400 XSendEvent(obt_display, moveresize_client->window, FALSE,
401 NoEventMask, &ce);
402
403 waiting_for_sync = TRUE;
404
405 obt_main_loop_timeout_remove(ob_main_loop, sync_timeout_func);
406 obt_main_loop_timeout_add(ob_main_loop, G_USEC_PER_SEC * 2,
407 sync_timeout_func,
408 NULL, NULL, NULL);
409 }
410 #endif
411
412 client_configure(moveresize_client, cur_x, cur_y, cur_w, cur_h,
413 TRUE, FALSE, FALSE);
414
415 /* this would be better with a fixed width font ... XXX can do it better
416 if there are 2 text boxes */
417 if (config_resize_popup_show == 2 || /* == "Always" */
418 (config_resize_popup_show == 1 && /* == "Nonpixel" */
419 moveresize_client->size_inc.width > 1 &&
420 moveresize_client->size_inc.height > 1))
421 popup_coords(moveresize_client, "%d x %d",
422 moveresize_client->logical_size.width,
423 moveresize_client->logical_size.height);
424 }
425
426 #ifdef SYNC
427 static gboolean sync_timeout_func(gpointer data)
428 {
429 waiting_for_sync = FALSE; /* we timed out waiting for our sync... */
430 do_resize(); /* ...so let any pending resizes through */
431
432 return FALSE; /* don't repeat */
433 }
434 #endif
435
436 static void calc_resize(gboolean keyboard, gint keydist, gint *dw, gint *dh,
437 ObDirection dir)
438 {
439 gint resist, x = 0, y = 0, lw, lh, ow, oh, nw, nh;
440 gint trydw, trydh;
441
442 ow = cur_w;
443 oh = cur_h;
444 nw = ow + *dw;
445 nh = oh + *dh;
446
447 if (!keyboard &&
448 (moveresize_client->max_ratio || moveresize_client->min_ratio))
449 {
450 switch (dir) {
451 case OB_DIRECTION_NORTH:
452 case OB_DIRECTION_SOUTH:
453 /* resize the width based on the height */
454 if (moveresize_client->min_ratio) {
455 if (nh * moveresize_client->min_ratio > nw)
456 nw = (gint)(nh * moveresize_client->min_ratio);
457 }
458 if (moveresize_client->max_ratio) {
459 if (nh * moveresize_client->max_ratio < nw)
460 nw = (gint)(nh * moveresize_client->max_ratio);
461 }
462 break;
463 default:
464 /* resize the height based on the width */
465 if (moveresize_client->min_ratio) {
466 if (nh * moveresize_client->min_ratio > nw)
467 nh = (gint)(nw / moveresize_client->min_ratio);
468 }
469 if (moveresize_client->max_ratio) {
470 if (nh * moveresize_client->max_ratio < nw)
471 nh = (gint)(nw / moveresize_client->max_ratio);
472 }
473 break;
474 }
475
476 /* see its actual size (apply aspect ratios) */
477 client_try_configure(moveresize_client, &x, &y, &nw, &nh, &lw, &lh,
478 TRUE);
479 trydw = nw - ow;
480 trydh = nh - oh;
481 }
482
483 /* resist_size_* needs the frame size */
484 nw += moveresize_client->frame->size.left +
485 moveresize_client->frame->size.right;
486 nh += moveresize_client->frame->size.top +
487 moveresize_client->frame->size.bottom;
488
489 if (keyboard) resist = keydist - 1; /* resist for one key press */
490 else resist = config_resist_win;
491 resist_size_windows(moveresize_client, resist, &nw, &nh, dir);
492 if (!keyboard) resist = config_resist_edge;
493 resist_size_monitors(moveresize_client, resist, &nw, &nh, dir);
494
495 nw -= moveresize_client->frame->size.left +
496 moveresize_client->frame->size.right;
497 nh -= moveresize_client->frame->size.top +
498 moveresize_client->frame->size.bottom;
499
500 *dw = nw - ow;
501 *dh = nh - oh;
502
503 /* take aspect ratios into account for resistance */
504 if (!keyboard &&
505 (moveresize_client->max_ratio || moveresize_client->min_ratio))
506 {
507 if (*dh != trydh) { /* got resisted */
508 /* resize the width based on the height */
509 if (moveresize_client->min_ratio) {
510 if (nh * moveresize_client->min_ratio > nw)
511 nw = (gint)(nh * moveresize_client->min_ratio);
512 }
513 if (moveresize_client->max_ratio) {
514 if (nh * moveresize_client->max_ratio < nw)
515 nw = (gint)(nh * moveresize_client->max_ratio);
516 }
517 }
518 if (*dw != trydw) { /* got resisted */
519 /* resize the height based on the width */
520 if (moveresize_client->min_ratio) {
521 if (nh * moveresize_client->min_ratio > nw)
522 nh = (gint)(nw / moveresize_client->min_ratio);
523 }
524 if (moveresize_client->max_ratio) {
525 if (nh * moveresize_client->max_ratio < nw)
526 nh = (gint)(nw / moveresize_client->max_ratio);
527 }
528 }
529 }
530
531 /* make sure it's all valid */
532 client_try_configure(moveresize_client, &x, &y, &nw, &nh, &lw, &lh, TRUE);
533
534 *dw = nw - ow;
535 *dh = nh - oh;
536 }
537
538 static gboolean edge_warp_delay_func(gpointer data)
539 {
540 guint d;
541
542 /* only fire every second time. so it's fast the first time, but slower
543 after that */
544 if (edge_warp_odd) {
545 d = screen_find_desktop(screen_desktop, edge_warp_dir, TRUE, FALSE);
546 if (d != screen_desktop) screen_set_desktop(d, TRUE);
547 }
548 edge_warp_odd = !edge_warp_odd;
549
550 return TRUE; /* do repeat ! */
551 }
552
553 static void do_edge_warp(gint x, gint y)
554 {
555 guint i;
556 ObDirection dir;
557
558 if (!config_mouse_screenedgetime) return;
559
560 dir = -1;
561
562 for (i = 0; i < screen_num_monitors; ++i) {
563 Rect *a = screen_physical_area_monitor(i);
564 if (x == RECT_LEFT(*a)) dir = OB_DIRECTION_WEST;
565 if (x == RECT_RIGHT(*a)) dir = OB_DIRECTION_EAST;
566 if (y == RECT_TOP(*a)) dir = OB_DIRECTION_NORTH;
567 if (y == RECT_BOTTOM(*a)) dir = OB_DIRECTION_SOUTH;
568
569 /* try check for xinerama boundaries */
570 if ((x + 1 == RECT_LEFT(*a) || x - 1 == RECT_RIGHT(*a)) &&
571 (dir == OB_DIRECTION_WEST || dir == OB_DIRECTION_EAST))
572 {
573 dir = -1;
574 }
575 if ((y + 1 == RECT_TOP(*a) || y - 1 == RECT_BOTTOM(*a)) &&
576 (dir == OB_DIRECTION_NORTH || dir == OB_DIRECTION_SOUTH))
577 {
578 dir = -1;
579 }
580 g_free(a);
581 }
582
583 if (dir != edge_warp_dir) {
584 cancel_edge_warp();
585 if (dir != (ObDirection)-1) {
586 edge_warp_odd = TRUE; /* switch on the first timeout */
587 obt_main_loop_timeout_add(ob_main_loop,
588 config_mouse_screenedgetime * 1000,
589 edge_warp_delay_func,
590 NULL, NULL, NULL);
591 }
592 edge_warp_dir = dir;
593 }
594 }
595
596 static void cancel_edge_warp(void)
597 {
598 obt_main_loop_timeout_remove(ob_main_loop, edge_warp_delay_func);
599 }
600
601 static void move_with_keys(gint keycode, gint state)
602 {
603 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
604 gint opx, px, opy, py;
605 gint dist = 0;
606
607 /* shift means jump to edge */
608 if (state & obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT)) {
609 gint x, y;
610 ObDirection dir;
611
612 if (keycode == ob_keycode(OB_KEY_RIGHT))
613 dir = OB_DIRECTION_EAST;
614 else if (keycode == ob_keycode(OB_KEY_LEFT))
615 dir = OB_DIRECTION_WEST;
616 else if (keycode == ob_keycode(OB_KEY_DOWN))
617 dir = OB_DIRECTION_SOUTH;
618 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
619 dir = OB_DIRECTION_NORTH;
620
621 client_find_move_directional(moveresize_client, dir, &x, &y);
622 dx = x - moveresize_client->area.x;
623 dy = y - moveresize_client->area.y;
624 } else {
625 /* control means fine grained */
626 if (state &
627 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL))
628 {
629 dist = 1;
630 }
631 else
632 dist = KEY_DIST;
633
634 if (keycode == ob_keycode(OB_KEY_RIGHT))
635 dx = dist;
636 else if (keycode == ob_keycode(OB_KEY_LEFT))
637 dx = -dist;
638 else if (keycode == ob_keycode(OB_KEY_DOWN))
639 dy = dist;
640 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
641 dy = -dist;
642 }
643
644 screen_pointer_pos(&opx, &opy);
645 XWarpPointer(obt_display, None, None, 0, 0, 0, 0, dx, dy);
646 /* steal the motion events this causes */
647 XSync(obt_display, FALSE);
648 {
649 XEvent ce;
650 while (XCheckTypedEvent(obt_display, MotionNotify, &ce));
651 }
652 screen_pointer_pos(&px, &py);
653
654 cur_x += dx;
655 cur_y += dy;
656 do_move(TRUE, dist);
657
658 /* because the cursor moves even though the window does
659 not nessesarily (resistance), this adjusts where the curor
660 thinks it started so that it keeps up with where the window
661 actually is */
662 start_x += (px - opx) - (cur_x - ox);
663 start_y += (py - opy) - (cur_y - oy);
664 }
665
666 static void resize_with_keys(gint keycode, gint state)
667 {
668 gint dw = 0, dh = 0, pdx = 0, pdy = 0, opx, opy, px, py;
669 gint dist = 0, resist = 0;
670 ObDirection dir;
671
672 /* pick the edge if it needs to move */
673 if (keycode == ob_keycode(OB_KEY_RIGHT)) {
674 dir = OB_DIRECTION_EAST;
675 if (key_resize_edge != OB_DIRECTION_WEST &&
676 key_resize_edge != OB_DIRECTION_EAST)
677 {
678 key_resize_edge = OB_DIRECTION_EAST;
679 return;
680 }
681 }
682 if (keycode == ob_keycode(OB_KEY_LEFT)) {
683 dir = OB_DIRECTION_WEST;
684 if (key_resize_edge != OB_DIRECTION_WEST &&
685 key_resize_edge != OB_DIRECTION_EAST)
686 {
687 key_resize_edge = OB_DIRECTION_WEST;
688 return;
689 }
690 }
691 if (keycode == ob_keycode(OB_KEY_UP)) {
692 dir = OB_DIRECTION_NORTH;
693 if (key_resize_edge != OB_DIRECTION_NORTH &&
694 key_resize_edge != OB_DIRECTION_SOUTH)
695 {
696 key_resize_edge = OB_DIRECTION_NORTH;
697 return;
698 }
699 }
700 if (keycode == ob_keycode(OB_KEY_DOWN)) {
701 dir = OB_DIRECTION_SOUTH;
702 if (key_resize_edge != OB_DIRECTION_NORTH &&
703 key_resize_edge != OB_DIRECTION_SOUTH)
704 {
705 key_resize_edge = OB_DIRECTION_SOUTH;
706 return;
707 }
708 }
709
710 /* shift means jump to edge */
711 if (state & obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT)) {
712 gint x, y, w, h;
713
714 if (keycode == ob_keycode(OB_KEY_RIGHT))
715 dir = OB_DIRECTION_EAST;
716 else if (keycode == ob_keycode(OB_KEY_LEFT))
717 dir = OB_DIRECTION_WEST;
718 else if (keycode == ob_keycode(OB_KEY_DOWN))
719 dir = OB_DIRECTION_SOUTH;
720 else /* if (keycode == ob_keycode(OB_KEY_UP)) */
721 dir = OB_DIRECTION_NORTH;
722
723 client_find_resize_directional(moveresize_client, key_resize_edge,
724 key_resize_edge == dir,
725 &x, &y, &w, &h);
726 dw = w - moveresize_client->area.width;
727 dh = h - moveresize_client->area.height;
728 } else {
729 gint distw, disth;
730
731 /* control means fine grained */
732 if (moveresize_client->size_inc.width > 1) {
733 distw = moveresize_client->size_inc.width;
734 resist = 1;
735 }
736 else if (state &
737 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL))
738 {
739 distw = 1;
740 resist = 1;
741 }
742 else {
743 distw = KEY_DIST;
744 resist = KEY_DIST;
745 }
746 if (moveresize_client->size_inc.height > 1) {
747 disth = moveresize_client->size_inc.height;
748 resist = 1;
749 }
750 else if (state &
751 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL))
752 {
753 disth = 1;
754 resist = 1;
755 }
756 else {
757 disth = KEY_DIST;
758 resist = KEY_DIST;
759 }
760
761 if (key_resize_edge == OB_DIRECTION_WEST) {
762 if (dir == OB_DIRECTION_WEST)
763 dw = (dist = distw);
764 else
765 dw = -(dist = distw);
766 }
767 else if (key_resize_edge == OB_DIRECTION_EAST) {
768 if (dir == OB_DIRECTION_EAST)
769 dw = (dist = distw);
770 else
771 dw = -(dist = distw);
772 }
773 else if (key_resize_edge == OB_DIRECTION_NORTH) {
774 if (dir == OB_DIRECTION_NORTH)
775 dh = (dist = disth);
776 else
777 dh = -(dist = disth);
778 }
779 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
780 if (dir == OB_DIRECTION_SOUTH)
781 dh = (dist = disth);
782 else
783 dh = -(dist = disth);
784 }
785 }
786
787 calc_resize(TRUE, resist, &dw, &dh, dir);
788 if (key_resize_edge == OB_DIRECTION_WEST)
789 cur_x -= dw;
790 else if (key_resize_edge == OB_DIRECTION_NORTH)
791 cur_y -= dh;
792 cur_w += dw;
793 cur_h += dh;
794
795 /* how to move the pointer to keep up with the change */
796 if (key_resize_edge == OB_DIRECTION_WEST)
797 pdx = -dw;
798 else if (key_resize_edge == OB_DIRECTION_EAST)
799 pdx = dw;
800 else if (key_resize_edge == OB_DIRECTION_NORTH)
801 pdy = -dh;
802 else if (key_resize_edge == OB_DIRECTION_SOUTH)
803 pdy = dh;
804
805 screen_pointer_pos(&opx, &opy);
806 XWarpPointer(obt_display, None, None, 0, 0, 0, 0, pdx, pdy);
807 /* steal the motion events this causes */
808 XSync(obt_display, FALSE);
809 {
810 XEvent ce;
811 while (XCheckTypedEvent(obt_display, MotionNotify, &ce));
812 }
813 screen_pointer_pos(&px, &py);
814
815 do_resize();
816
817 /* because the cursor moves even though the window does
818 not nessesarily (resistance), this adjusts where the cursor
819 thinks it started so that it keeps up with where the window
820 actually is */
821 start_x += (px - opx) - dw;
822 start_y += (py - opy) - dh;
823
824 }
825
826 gboolean moveresize_event(XEvent *e)
827 {
828 gboolean used = FALSE;
829
830 if (!moveresize_in_progress) return FALSE;
831
832 if (e->type == ButtonPress) {
833 if (!button) {
834 start_x = e->xbutton.x_root;
835 start_y = e->xbutton.y_root;
836 button = e->xbutton.button; /* this will end it now */
837 }
838 used = e->xbutton.button == button;
839 } else if (e->type == ButtonRelease) {
840 if (!button || e->xbutton.button == button) {
841 moveresize_end(FALSE);
842 used = TRUE;
843 }
844 } else if (e->type == MotionNotify) {
845 if (moving) {
846 cur_x = start_cx + e->xmotion.x_root - start_x;
847 cur_y = start_cy + e->xmotion.y_root - start_y;
848 do_move(FALSE, 0);
849 do_edge_warp(e->xmotion.x_root, e->xmotion.y_root);
850 } else {
851 gint dw, dh;
852 ObDirection dir;
853
854 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT)) {
855 dw = -(e->xmotion.x_root - start_x);
856 dh = -(e->xmotion.y_root - start_y);
857 dir = OB_DIRECTION_NORTHWEST;
858 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP)) {
859 dw = 0;
860 dh = -(e->xmotion.y_root - start_y);
861 dir = OB_DIRECTION_NORTH;
862 } else if (corner ==
863 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT)) {
864 dw = (e->xmotion.x_root - start_x);
865 dh = -(e->xmotion.y_root - start_y);
866 dir = OB_DIRECTION_NORTHEAST;
867 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT)) {
868 dw = (e->xmotion.x_root - start_x);
869 dh = 0;
870 dir = OB_DIRECTION_EAST;
871 } else if (corner ==
872 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT)) {
873 dw = (e->xmotion.x_root - start_x);
874 dh = (e->xmotion.y_root - start_y);
875 dir = OB_DIRECTION_SOUTHEAST;
876 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM))
877 {
878 dw = 0;
879 dh = (e->xmotion.y_root - start_y);
880 dir = OB_DIRECTION_SOUTH;
881 } else if (corner ==
882 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT)) {
883 dw = -(e->xmotion.x_root - start_x);
884 dh = (e->xmotion.y_root - start_y);
885 dir = OB_DIRECTION_SOUTHWEST;
886 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT)) {
887 dw = -(e->xmotion.x_root - start_x);
888 dh = 0;
889 dir = OB_DIRECTION_WEST;
890 } else if (corner ==
891 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD)) {
892 dw = (e->xmotion.x_root - start_x);
893 dh = (e->xmotion.y_root - start_y);
894 dir = OB_DIRECTION_SOUTHEAST;
895 } else
896 g_assert_not_reached();
897
898 dw -= cur_w - start_cw;
899 dh -= cur_h - start_ch;
900
901 calc_resize(FALSE, 0, &dw, &dh, dir);
902 cur_w += dw;
903 cur_h += dh;
904
905 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT) ||
906 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT) ||
907 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT))
908 {
909 cur_x -= dw;
910 }
911 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT) ||
912 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP) ||
913 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT))
914 {
915 cur_y -= dh;
916 }
917
918 do_resize();
919 }
920 used = TRUE;
921 } else if (e->type == KeyPress) {
922 if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
923 moveresize_end(TRUE);
924 used = TRUE;
925 } else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
926 moveresize_end(FALSE);
927 used = TRUE;
928 } else if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT) ||
929 e->xkey.keycode == ob_keycode(OB_KEY_LEFT) ||
930 e->xkey.keycode == ob_keycode(OB_KEY_DOWN) ||
931 e->xkey.keycode == ob_keycode(OB_KEY_UP))
932 {
933 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD)) {
934 resize_with_keys(e->xkey.keycode, e->xkey.state);
935 used = TRUE;
936 } else if (corner ==
937 OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD))
938 {
939 move_with_keys(e->xkey.keycode, e->xkey.state);
940 used = TRUE;
941 }
942 }
943 }
944 #ifdef SYNC
945 else if (e->type == obt_display_extension_sync_basep + XSyncAlarmNotify)
946 {
947 waiting_for_sync = FALSE; /* we got our sync... */
948 do_resize(); /* ...so try resize if there is more change pending */
949 used = TRUE;
950 }
951 #endif
952 return used;
953 }
This page took 0.083531 seconds and 5 git commands to generate.