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