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