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