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