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