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