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