]> Dogcows Code - chaz/openbox/blob - openbox/moveresize.c
Use GMainLoop instead of ObtMainLoop
[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/xqueue.h"
36 #include "obt/prop.h"
37 #include "obt/keyboard.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 #define SYNC_TIMEOUTS 4
45
46 gboolean moveresize_in_progress = FALSE;
47 ObClient *moveresize_client = NULL;
48 #ifdef SYNC
49 XSyncAlarm moveresize_alarm = None;
50 #endif
51
52 static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */
53
54 /* starting geometry for the window being moved/resized, so it can be
55 restored */
56 static gint start_x, start_y, start_cx, start_cy, start_cw, start_ch;
57 static gboolean was_max_horz, was_max_vert;
58 static Rect pre_max_area;
59 static gint cur_x, cur_y, cur_w, cur_h;
60 static guint button;
61 static guint32 corner;
62 static ObDirection edge_warp_dir = -1;
63 static gboolean edge_warp_odd = FALSE;
64 static guint edge_warp_timer = 0;
65 static ObDirection key_resize_edge = -1;
66 #ifdef SYNC
67 static guint waiting_for_sync;
68 static guint sync_timer = 0;
69 #endif
70
71 static ObPopup *popup = NULL;
72
73 static void do_move(gboolean keyboard, gint keydist);
74 static void do_resize(void);
75 static void do_edge_warp(gint x, gint y);
76 static void cancel_edge_warp();
77 #ifdef SYNC
78 static gboolean sync_timeout_func(gpointer data);
79 #endif
80
81 static void client_dest(ObClient *client, gpointer data)
82 {
83 if (moveresize_client == client)
84 moveresize_end(TRUE);
85 }
86
87 void moveresize_startup(gboolean reconfig)
88 {
89 popup = popup_new();
90 popup_set_text_align(popup, RR_JUSTIFY_CENTER);
91
92 if (!reconfig)
93 client_add_destroy_notify(client_dest, NULL);
94 }
95
96 void moveresize_shutdown(gboolean reconfig)
97 {
98 if (!reconfig) {
99 if (moveresize_in_progress)
100 moveresize_end(FALSE);
101 client_remove_destroy_notify(client_dest);
102 }
103
104 popup_free(popup);
105 popup = NULL;
106 }
107
108 static void popup_coords(ObClient *c, const gchar *format, gint a, gint b)
109 {
110 gchar *text;
111
112 text = g_strdup_printf(format, a, b);
113 if (config_resize_popup_pos == OB_RESIZE_POS_TOP)
114 popup_position(popup, SouthGravity,
115 c->frame->area.x
116 + c->frame->area.width/2,
117 c->frame->area.y - ob_rr_theme->fbwidth);
118 else if (config_resize_popup_pos == OB_RESIZE_POS_CENTER)
119 popup_position(popup, CenterGravity,
120 c->frame->area.x + c->frame->area.width / 2,
121 c->frame->area.y + c->frame->area.height / 2);
122 else /* Fixed */ {
123 const Rect *area = screen_physical_area_active();
124 gint gravity, x, y;
125
126 x = config_resize_popup_fixed.x.pos;
127 if (config_resize_popup_fixed.x.center)
128 x = area->x + area->width/2;
129 else if (config_resize_popup_fixed.x.opposite)
130 x = RECT_RIGHT(*area) - x;
131 else
132 x = area->x + x;
133
134 y = config_resize_popup_fixed.y.pos;
135 if (config_resize_popup_fixed.y.center)
136 y = area->y + area->height/2;
137 else if (config_resize_popup_fixed.y.opposite)
138 y = RECT_RIGHT(*area) - y;
139 else
140 y = area->y + y;
141
142 if (config_resize_popup_fixed.x.center) {
143 if (config_resize_popup_fixed.y.center)
144 gravity = CenterGravity;
145 else if (config_resize_popup_fixed.y.opposite)
146 gravity = SouthGravity;
147 else
148 gravity = NorthGravity;
149 }
150 else if (config_resize_popup_fixed.x.opposite) {
151 if (config_resize_popup_fixed.y.center)
152 gravity = EastGravity;
153 else if (config_resize_popup_fixed.y.opposite)
154 gravity = SouthEastGravity;
155 else
156 gravity = NorthEastGravity;
157 }
158 else {
159 if (config_resize_popup_fixed.y.center)
160 gravity = WestGravity;
161 else if (config_resize_popup_fixed.y.opposite)
162 gravity = SouthWestGravity;
163 else
164 gravity = NorthWestGravity;
165 }
166
167 popup_position(popup, gravity, x, y);
168 }
169 popup_show(popup, text);
170 g_free(text);
171 }
172
173 void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
174 {
175 ObCursor cur;
176 gboolean mv = (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE) ||
177 cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD));
178 gint up = 1;
179 gint left = 1;
180
181 if (moveresize_in_progress || !c->frame->visible ||
182 !(mv ?
183 (c->functions & OB_CLIENT_FUNC_MOVE) :
184 (c->functions & OB_CLIENT_FUNC_RESIZE)))
185 return;
186
187 if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT)) {
188 cur = OB_CURSOR_NORTHWEST;
189 up = left = -1;
190 }
191 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP)) {
192 cur = OB_CURSOR_NORTH;
193 up = -1;
194 }
195 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT)) {
196 cur = OB_CURSOR_NORTHEAST;
197 up = -1;
198 }
199 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT))
200 cur = OB_CURSOR_EAST;
201 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT))
202 cur = OB_CURSOR_SOUTHEAST;
203 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM))
204 cur = OB_CURSOR_SOUTH;
205 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT)) {
206 cur = OB_CURSOR_SOUTHWEST;
207 left = -1;
208 }
209 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT)) {
210 cur = OB_CURSOR_WEST;
211 left = -1;
212 }
213 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD))
214 cur = OB_CURSOR_SOUTHEAST;
215 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE))
216 cur = OB_CURSOR_MOVE;
217 else if (cnr == OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD))
218 cur = OB_CURSOR_MOVE;
219 else
220 g_assert_not_reached();
221
222 /* keep the pointer bounded to the screen for move/resize */
223 if (!grab_pointer(FALSE, TRUE, cur))
224 return;
225 if (!grab_keyboard()) {
226 ungrab_pointer();
227 return;
228 }
229
230 frame_end_iconify_animation(c->frame);
231
232 moving = mv;
233 moveresize_client = c;
234 start_cx = c->area.x;
235 start_cy = c->area.y;
236 start_cw = c->area.width;
237 start_ch = c->area.height;
238 /* these adjustments for the size_inc make resizing a terminal more
239 friendly. you essentially start the resize in the middle of the
240 increment instead of at 0, so you have to move half an increment
241 either way instead of a full increment one and 1 px the other. */
242 start_x = x - (mv ? 0 : left * c->size_inc.width / 2);
243 start_y = y - (mv ? 0 : up * c->size_inc.height / 2);
244 corner = cnr;
245 button = b;
246 key_resize_edge = -1;
247
248 /* default to not putting max back on cancel */
249 was_max_horz = was_max_vert = FALSE;
250
251 /*
252 have to change start_cx and start_cy if going to do this..
253 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
254 corner == prop_atoms.net_wm_moveresize_size_keyboard)
255 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
256 c->area.width / 2, c->area.height / 2);
257 */
258
259 cur_x = start_cx;
260 cur_y = start_cy;
261 cur_w = start_cw;
262 cur_h = start_ch;
263
264 moveresize_in_progress = TRUE;
265
266 #ifdef SYNC
267 if (config_resize_redraw && !moving && obt_display_extension_sync &&
268 moveresize_client->sync_request && moveresize_client->sync_counter &&
269 !moveresize_client->not_responding)
270 {
271 /* Initialize values for the resize syncing, and create an alarm for
272 the client's xsync counter */
273
274 XSyncValue val;
275 XSyncAlarmAttributes aa;
276
277 /* set the counter to an initial value */
278 XSyncIntToValue(&val, 0);
279 XSyncSetCounter(obt_display, moveresize_client->sync_counter, val);
280
281 /* this will be incremented when we tell the client what we're
282 looking for */
283 moveresize_client->sync_counter_value = 0;
284
285 /* the next sequence we're waiting for with the alarm */
286 XSyncIntToValue(&val, 1);
287
288 /* set an alarm on the counter */
289 aa.trigger.counter = moveresize_client->sync_counter;
290 aa.trigger.wait_value = val;
291 aa.trigger.value_type = XSyncAbsolute;
292 aa.trigger.test_type = XSyncPositiveTransition;
293 aa.events = True;
294 XSyncIntToValue(&aa.delta, 1);
295 moveresize_alarm = XSyncCreateAlarm(obt_display,
296 XSyncCACounter |
297 XSyncCAValue |
298 XSyncCAValueType |
299 XSyncCATestType |
300 XSyncCADelta |
301 XSyncCAEvents,
302 &aa);
303
304 waiting_for_sync = 0;
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 - 1;
587 break;
588 case OB_DIRECTION_EAST:
589 x = a->x;
590 break;
591 case OB_DIRECTION_SOUTH:
592 y = a->y;
593 break;
594 case OB_DIRECTION_WEST:
595 x = a->width - 1;
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 if (x == RECT_LEFT(*a)) dir = OB_DIRECTION_WEST;
634 if (x == RECT_RIGHT(*a)) dir = OB_DIRECTION_EAST;
635 if (y == RECT_TOP(*a)) dir = OB_DIRECTION_NORTH;
636 if (y == RECT_BOTTOM(*a)) dir = OB_DIRECTION_SOUTH;
637
638 /* try check for xinerama boundaries */
639 if ((x + 1 == RECT_LEFT(*a) || x - 1 == RECT_RIGHT(*a)) &&
640 (dir == OB_DIRECTION_WEST || dir == OB_DIRECTION_EAST))
641 {
642 dir = -1;
643 }
644 if ((y + 1 == RECT_TOP(*a) || y - 1 == RECT_BOTTOM(*a)) &&
645 (dir == OB_DIRECTION_NORTH || dir == OB_DIRECTION_SOUTH))
646 {
647 dir = -1;
648 }
649 }
650
651 if (dir != edge_warp_dir) {
652 cancel_edge_warp();
653 if (dir != (ObDirection)-1) {
654 edge_warp_odd = TRUE; /* switch on the first timeout */
655 edge_warp_timer = g_timeout_add(config_mouse_screenedgetime,
656 edge_warp_delay_func, NULL);
657 }
658 edge_warp_dir = dir;
659 }
660 }
661
662 static void cancel_edge_warp(void)
663 {
664 if (edge_warp_timer) g_source_remove(edge_warp_timer);
665 edge_warp_timer = 0;
666 }
667
668 static void move_with_keys(KeySym sym, guint state)
669 {
670 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
671 gint opx, px, opy, py;
672 gint dist = 0;
673
674 /* shift means jump to edge */
675 if (state & obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT))
676 {
677 gint x, y;
678 ObDirection dir;
679
680 if (sym == XK_Right)
681 dir = OB_DIRECTION_EAST;
682 else if (sym == XK_Left)
683 dir = OB_DIRECTION_WEST;
684 else if (sym == XK_Down)
685 dir = OB_DIRECTION_SOUTH;
686 else /* sym == XK_Up */
687 dir = OB_DIRECTION_NORTH;
688
689 client_find_move_directional(moveresize_client, dir, &x, &y);
690 dx = x - moveresize_client->area.x;
691 dy = y - moveresize_client->area.y;
692 } else {
693 /* control means fine grained */
694 if (state &
695 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL))
696 {
697 dist = 1;
698 }
699 else
700 dist = KEY_DIST;
701
702 if (sym == XK_Right)
703 dx = dist;
704 else if (sym == XK_Left)
705 dx = -dist;
706 else if (sym == XK_Down)
707 dy = dist;
708 else /* if (sym == XK_Up) */
709 dy = -dist;
710 }
711
712 screen_pointer_pos(&opx, &opy);
713 XWarpPointer(obt_display, None, None, 0, 0, 0, 0, dx, dy);
714 /* steal the motion events this causes */
715 XSync(obt_display, FALSE);
716 {
717 XEvent ce;
718 while (xqueue_remove_local(&ce, xqueue_match_type,
719 GINT_TO_POINTER(MotionNotify)));
720 }
721 screen_pointer_pos(&px, &py);
722
723 cur_x += dx;
724 cur_y += dy;
725 do_move(TRUE, dist);
726
727 /* because the cursor moves even though the window does
728 not nessesarily (resistance), this adjusts where the curor
729 thinks it started so that it keeps up with where the window
730 actually is */
731 start_x += (px - opx) - (cur_x - ox);
732 start_y += (py - opy) - (cur_y - oy);
733 }
734
735 static void resize_with_keys(KeySym sym, guint state)
736 {
737 gint dw = 0, dh = 0, pdx = 0, pdy = 0, opx, opy, px, py;
738 gint resist = 0;
739 ObDirection dir;
740
741 /* pick the edge if it needs to move */
742 if (sym == XK_Right) {
743 dir = OB_DIRECTION_EAST;
744 if (key_resize_edge != OB_DIRECTION_WEST &&
745 key_resize_edge != OB_DIRECTION_EAST)
746 {
747 key_resize_edge = OB_DIRECTION_EAST;
748 return;
749 }
750 } else if (sym == XK_Left) {
751 dir = OB_DIRECTION_WEST;
752 if (key_resize_edge != OB_DIRECTION_WEST &&
753 key_resize_edge != OB_DIRECTION_EAST)
754 {
755 key_resize_edge = OB_DIRECTION_WEST;
756 return;
757 }
758 } else if (sym == XK_Up) {
759 dir = OB_DIRECTION_NORTH;
760 if (key_resize_edge != OB_DIRECTION_NORTH &&
761 key_resize_edge != OB_DIRECTION_SOUTH)
762 {
763 key_resize_edge = OB_DIRECTION_NORTH;
764 return;
765 }
766 } else /* if (sym == XK_Down) */ {
767 dir = OB_DIRECTION_SOUTH;
768 if (key_resize_edge != OB_DIRECTION_NORTH &&
769 key_resize_edge != OB_DIRECTION_SOUTH)
770 {
771 key_resize_edge = OB_DIRECTION_SOUTH;
772 return;
773 }
774 }
775
776 /* shift means jump to edge */
777 if (state & obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT))
778 {
779 gint x, y, w, h;
780
781 if (sym == XK_Right)
782 dir = OB_DIRECTION_EAST;
783 else if (sym == XK_Left)
784 dir = OB_DIRECTION_WEST;
785 else if (sym == XK_Down)
786 dir = OB_DIRECTION_SOUTH;
787 else /* if (sym == XK_Up)) */
788 dir = OB_DIRECTION_NORTH;
789
790 client_find_resize_directional(moveresize_client, key_resize_edge,
791 key_resize_edge == dir,
792 &x, &y, &w, &h);
793 dw = w - moveresize_client->area.width;
794 dh = h - moveresize_client->area.height;
795 } else {
796 gint distw, disth;
797
798 /* control means fine grained */
799 if (moveresize_client->size_inc.width > 1) {
800 distw = moveresize_client->size_inc.width;
801 resist = 1;
802 }
803 else if (state &
804 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL))
805 {
806 distw = 1;
807 resist = 1;
808 }
809 else {
810 distw = KEY_DIST;
811 resist = KEY_DIST;
812 }
813 if (moveresize_client->size_inc.height > 1) {
814 disth = moveresize_client->size_inc.height;
815 resist = 1;
816 }
817 else if (state &
818 obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_CONTROL))
819 {
820 disth = 1;
821 resist = 1;
822 }
823 else {
824 disth = KEY_DIST;
825 resist = KEY_DIST;
826 }
827
828 if (key_resize_edge == OB_DIRECTION_WEST) {
829 if (dir == OB_DIRECTION_WEST)
830 dw = distw;
831 else
832 dw = -distw;
833 }
834 else if (key_resize_edge == OB_DIRECTION_EAST) {
835 if (dir == OB_DIRECTION_EAST)
836 dw = distw;
837 else
838 dw = -distw;
839 }
840 else if (key_resize_edge == OB_DIRECTION_NORTH) {
841 if (dir == OB_DIRECTION_NORTH)
842 dh = disth;
843 else
844 dh = -disth;
845 }
846 else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ {
847 if (dir == OB_DIRECTION_SOUTH)
848 dh = disth;
849 else
850 dh = -disth;
851 }
852 }
853
854 if (moveresize_client->max_horz &&
855 (key_resize_edge == OB_DIRECTION_WEST ||
856 key_resize_edge == OB_DIRECTION_EAST))
857 {
858 /* unmax horz */
859 was_max_horz = TRUE;
860 pre_max_area.x = moveresize_client->pre_max_area.x;
861 pre_max_area.width = moveresize_client->pre_max_area.width;
862
863 moveresize_client->pre_max_area.x = cur_x;
864 moveresize_client->pre_max_area.width = cur_w;
865 client_maximize(moveresize_client, FALSE, 1);
866 }
867 else if (moveresize_client->max_vert &&
868 (key_resize_edge == OB_DIRECTION_NORTH ||
869 key_resize_edge == OB_DIRECTION_SOUTH))
870 {
871 /* unmax vert */
872 was_max_vert = TRUE;
873 pre_max_area.y = moveresize_client->pre_max_area.y;
874 pre_max_area.height = moveresize_client->pre_max_area.height;
875
876 moveresize_client->pre_max_area.y = cur_y;
877 moveresize_client->pre_max_area.height = cur_h;
878 client_maximize(moveresize_client, FALSE, 2);
879 }
880
881 calc_resize(TRUE, resist, &dw, &dh, dir);
882 if (key_resize_edge == OB_DIRECTION_WEST)
883 cur_x -= dw;
884 else if (key_resize_edge == OB_DIRECTION_NORTH)
885 cur_y -= dh;
886 cur_w += dw;
887 cur_h += dh;
888
889 /* how to move the pointer to keep up with the change */
890 if (key_resize_edge == OB_DIRECTION_WEST)
891 pdx = -dw;
892 else if (key_resize_edge == OB_DIRECTION_EAST)
893 pdx = dw;
894 else if (key_resize_edge == OB_DIRECTION_NORTH)
895 pdy = -dh;
896 else if (key_resize_edge == OB_DIRECTION_SOUTH)
897 pdy = dh;
898
899 screen_pointer_pos(&opx, &opy);
900 XWarpPointer(obt_display, None, None, 0, 0, 0, 0, pdx, pdy);
901 /* steal the motion events this causes */
902 XSync(obt_display, FALSE);
903 {
904 XEvent ce;
905 while (xqueue_remove_local(&ce, xqueue_match_type,
906 GINT_TO_POINTER(MotionNotify)));
907 }
908 screen_pointer_pos(&px, &py);
909
910 do_resize();
911
912 /* because the cursor moves even though the window does
913 not nessesarily (resistance), this adjusts where the cursor
914 thinks it started so that it keeps up with where the window
915 actually is */
916 start_x += (px - opx) - dw;
917 start_y += (py - opy) - dh;
918
919 }
920
921 gboolean moveresize_event(XEvent *e)
922 {
923 gboolean used = FALSE;
924
925 if (!moveresize_in_progress) return FALSE;
926
927 if (e->type == ButtonPress) {
928 if (!button) {
929 start_x = e->xbutton.x_root;
930 start_y = e->xbutton.y_root;
931 button = e->xbutton.button; /* this will end it now */
932 }
933 used = e->xbutton.button == button;
934 } else if (e->type == ButtonRelease) {
935 if (!button || e->xbutton.button == button) {
936 moveresize_end(FALSE);
937 used = TRUE;
938 }
939 } else if (e->type == MotionNotify) {
940 if (moving) {
941 cur_x = start_cx + e->xmotion.x_root - start_x;
942 cur_y = start_cy + e->xmotion.y_root - start_y;
943 do_move(FALSE, 0);
944 do_edge_warp(e->xmotion.x_root, e->xmotion.y_root);
945 } else {
946 gint dw, dh;
947 ObDirection dir;
948
949 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT)) {
950 dw = -(e->xmotion.x_root - start_x);
951 dh = -(e->xmotion.y_root - start_y);
952 dir = OB_DIRECTION_NORTHWEST;
953 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP)) {
954 dw = 0;
955 dh = -(e->xmotion.y_root - start_y);
956 dir = OB_DIRECTION_NORTH;
957 } else if (corner ==
958 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT)) {
959 dw = (e->xmotion.x_root - start_x);
960 dh = -(e->xmotion.y_root - start_y);
961 dir = OB_DIRECTION_NORTHEAST;
962 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT)) {
963 dw = (e->xmotion.x_root - start_x);
964 dh = 0;
965 dir = OB_DIRECTION_EAST;
966 } else if (corner ==
967 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT)) {
968 dw = (e->xmotion.x_root - start_x);
969 dh = (e->xmotion.y_root - start_y);
970 dir = OB_DIRECTION_SOUTHEAST;
971 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM))
972 {
973 dw = 0;
974 dh = (e->xmotion.y_root - start_y);
975 dir = OB_DIRECTION_SOUTH;
976 } else if (corner ==
977 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT)) {
978 dw = -(e->xmotion.x_root - start_x);
979 dh = (e->xmotion.y_root - start_y);
980 dir = OB_DIRECTION_SOUTHWEST;
981 } else if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT)) {
982 dw = -(e->xmotion.x_root - start_x);
983 dh = 0;
984 dir = OB_DIRECTION_WEST;
985 } else if (corner ==
986 OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD)) {
987 dw = (e->xmotion.x_root - start_x);
988 dh = (e->xmotion.y_root - start_y);
989 dir = OB_DIRECTION_SOUTHEAST;
990 } else
991 g_assert_not_reached();
992
993 /* override the client's max state if desired */
994 if (ABS(dw) >= config_resist_edge) {
995 if (moveresize_client->max_horz) {
996 /* unmax horz */
997 was_max_horz = TRUE;
998 pre_max_area.x = moveresize_client->pre_max_area.x;
999 pre_max_area.width = moveresize_client->pre_max_area.width;
1000
1001 moveresize_client->pre_max_area.x = cur_x;
1002 moveresize_client->pre_max_area.width = cur_w;
1003 client_maximize(moveresize_client, FALSE, 1);
1004 }
1005 }
1006 else if (was_max_horz && !moveresize_client->max_horz) {
1007 /* remax horz and put the premax back */
1008 client_maximize(moveresize_client, TRUE, 1);
1009 moveresize_client->pre_max_area.x = pre_max_area.x;
1010 moveresize_client->pre_max_area.width = pre_max_area.width;
1011 }
1012
1013 if (ABS(dh) >= config_resist_edge) {
1014 if (moveresize_client->max_vert) {
1015 /* unmax vert */
1016 was_max_vert = TRUE;
1017 pre_max_area.y = moveresize_client->pre_max_area.y;
1018 pre_max_area.height =
1019 moveresize_client->pre_max_area.height;
1020
1021 moveresize_client->pre_max_area.y = cur_y;
1022 moveresize_client->pre_max_area.height = cur_h;
1023 client_maximize(moveresize_client, FALSE, 2);
1024 }
1025 }
1026 else if (was_max_vert && !moveresize_client->max_vert) {
1027 /* remax vert and put the premax back */
1028 client_maximize(moveresize_client, TRUE, 2);
1029 moveresize_client->pre_max_area.y = pre_max_area.y;
1030 moveresize_client->pre_max_area.height = pre_max_area.height;
1031 }
1032
1033 dw -= cur_w - start_cw;
1034 dh -= cur_h - start_ch;
1035
1036 calc_resize(FALSE, 0, &dw, &dh, dir);
1037 cur_w += dw;
1038 cur_h += dh;
1039
1040 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT) ||
1041 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT) ||
1042 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT))
1043 {
1044 cur_x -= dw;
1045 }
1046 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT) ||
1047 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP) ||
1048 corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT))
1049 {
1050 cur_y -= dh;
1051 }
1052
1053 do_resize();
1054 }
1055 used = TRUE;
1056 } else if (e->type == KeyPress) {
1057 KeySym sym = obt_keyboard_keypress_to_keysym(e);
1058
1059 if (sym == XK_Escape) {
1060 moveresize_end(TRUE);
1061 used = TRUE;
1062 } else if (sym == XK_Return || sym == XK_KP_Enter) {
1063 moveresize_end(FALSE);
1064 used = TRUE;
1065 } else if (sym == XK_Right || sym == XK_Left ||
1066 sym == XK_Up || sym == XK_Down)
1067 {
1068 if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD)) {
1069 resize_with_keys(sym, e->xkey.state);
1070 used = TRUE;
1071 } else if (corner ==
1072 OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD))
1073 {
1074 move_with_keys(sym, e->xkey.state);
1075 used = TRUE;
1076 }
1077 }
1078 }
1079 #ifdef SYNC
1080 else if (e->type == obt_display_extension_sync_basep + XSyncAlarmNotify)
1081 {
1082 waiting_for_sync = 0; /* we got our sync... */
1083 do_resize(); /* ...so try resize if there is more change pending */
1084 used = TRUE;
1085 }
1086 #endif
1087 return used;
1088 }
This page took 0.081955 seconds and 4 git commands to generate.