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