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