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