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