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