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