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