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