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