Change to the linux kernel coding style
[wmaker-crm.git] / src / moveres.c
1 /*
2 * Window Maker window manager
3 *
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 * USA.
20 */
21
22 #include "wconfig.h"
23
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
26 #include <X11/keysym.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
31
32 #include "WindowMaker.h"
33 #include "wcore.h"
34 #include "framewin.h"
35 #include "window.h"
36 #include "client.h"
37 #include "icon.h"
38 #include "dock.h"
39 #include "funcs.h"
40 #include "actions.h"
41 #include "workspace.h"
42
43 #include "geomview.h"
44 #include "screen.h"
45 #include "xinerama.h"
46
47 #include <WINGs/WINGsP.h>
48
49 /* How many different types of geometry/position
50 display thingies are there? */
51 #define NUM_DISPLAYS 5
52
53 #define LEFT 1
54 #define RIGHT 2
55 #define HORIZONTAL (LEFT|RIGHT)
56 #define UP 4
57 #define DOWN 8
58 #define VERTICAL (UP|DOWN)
59
60 /* True if window currently has a border. This also includes borderless
61 * windows which are currently selected
62 */
63 #define HAS_BORDER_WITH_SELECT(w) ((w)->flags.selected || HAS_BORDER(w))
64
65 /****** Global Variables ******/
66 extern Time LastTimestamp;
67
68 extern Cursor wCursor[WCUR_LAST];
69
70 extern WPreferences wPreferences;
71
72 extern Atom _XA_WM_PROTOCOLS;
73
74 /*
75 *----------------------------------------------------------------------
76 * checkMouseSamplingRate-
77 * For lowering the mouse motion sampling rate for machines where
78 * it's too high (SGIs). If it returns False then the event should be
79 * ignored.
80 *----------------------------------------------------------------------
81 */
82 static Bool checkMouseSamplingRate(XEvent * ev)
83 {
84 static Time previousMotion = 0;
85
86 if (ev->type == MotionNotify) {
87 if (ev->xmotion.time - previousMotion < DELAY_BETWEEN_MOUSE_SAMPLING) {
88 return False;
89 } else {
90 previousMotion = ev->xmotion.time;
91 }
92 }
93 return True;
94 }
95
96 /*
97 *----------------------------------------------------------------------
98 * moveGeometryDisplayCentered
99 *
100 * routine that moves the geometry/position window on scr so it is
101 * centered over the given coordinates (x,y). Also the window position
102 * is clamped so it stays on the screen at all times.
103 *----------------------------------------------------------------------
104 */
105 static void moveGeometryDisplayCentered(WScreen * scr, int x, int y)
106 {
107 unsigned int w = WMWidgetWidth(scr->gview);
108 unsigned int h = WMWidgetHeight(scr->gview);
109 int x1 = 0, y1 = 0, x2 = scr->scr_width, y2 = scr->scr_height;
110
111 x -= w / 2;
112 y -= h / 2;
113
114 /* dead area check */
115 if (scr->xine_info.count) {
116 WMRect rect;
117 int head, flags;
118
119 rect.pos.x = x;
120 rect.pos.y = y;
121 rect.size.width = w;
122 rect.size.height = h;
123
124 head = wGetRectPlacementInfo(scr, rect, &flags);
125
126 if (flags & (XFLAG_DEAD | XFLAG_PARTIAL)) {
127 rect = wGetRectForHead(scr, head);
128 x1 = rect.pos.x;
129 y1 = rect.pos.y;
130 x2 = x1 + rect.size.width;
131 y2 = y1 + rect.size.height;
132 }
133 }
134
135 if (x < x1 + 1)
136 x = x1 + 1;
137 else if (x > (x2 - w))
138 x = x2 - w;
139
140 if (y < y1 + 1)
141 y = y1 + 1;
142 else if (y > (y2 - h))
143 y = y2 - h;
144
145 WMMoveWidget(scr->gview, x, y);
146 }
147
148 static void showPosition(WWindow * wwin, int x, int y)
149 {
150 WScreen *scr = wwin->screen_ptr;
151
152 if (wPreferences.move_display == WDIS_NEW) {
153 #if 0
154 int width = wwin->frame->core->width;
155 int height = wwin->frame->core->height;
156
157 GC lgc = scr->line_gc;
158 XSetForeground(dpy, lgc, scr->line_pixel);
159 sprintf(num, "%i", x);
160
161 XDrawLine(dpy, scr->root_win, lgc, 0, y - 1, scr->scr_width, y - 1);
162 XDrawLine(dpy, scr->root_win, lgc, 0, y + height + 2, scr->scr_width, y + height + 2);
163 XDrawLine(dpy, scr->root_win, lgc, x - 1, 0, x - 1, scr->scr_height);
164 XDrawLine(dpy, scr->root_win, lgc, x + width + 2, 0, x + width + 2, scr->scr_height);
165 #endif
166 } else {
167 #ifdef VIRTUAL_DESKTOP
168 WSetGeometryViewShownPosition(scr->gview,
169 x + scr->workspaces[scr->current_workspace]->view_x,
170 y + scr->workspaces[scr->current_workspace]->view_y);
171 #else
172 WSetGeometryViewShownPosition(scr->gview, x, y);
173 #endif
174 }
175 }
176
177 static void cyclePositionDisplay(WWindow * wwin, int x, int y, int w, int h)
178 {
179 WScreen *scr = wwin->screen_ptr;
180 WMRect rect;
181
182 wPreferences.move_display++;
183 wPreferences.move_display %= NUM_DISPLAYS;
184
185 if (wPreferences.move_display == WDIS_NEW) {
186 wPreferences.move_display++;
187 wPreferences.move_display %= NUM_DISPLAYS;
188 }
189
190 if (wPreferences.move_display == WDIS_NONE) {
191 WMUnmapWidget(scr->gview);
192 } else {
193 if (wPreferences.move_display == WDIS_CENTER) {
194 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
195 moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width / 2,
196 rect.pos.y + rect.size.height / 2);
197 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
198 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
199 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
200 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
201 moveGeometryDisplayCentered(scr, x + w / 2, y + h / 2);
202 }
203 WMMapWidget(scr->gview);
204 }
205 }
206
207 static void mapPositionDisplay(WWindow * wwin, int x, int y, int w, int h)
208 {
209 WScreen *scr = wwin->screen_ptr;
210 WMRect rect;
211
212 if (wPreferences.move_display == WDIS_NEW || wPreferences.move_display == WDIS_NONE) {
213 return;
214 } else if (wPreferences.move_display == WDIS_CENTER) {
215 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
216 moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width / 2,
217 rect.pos.y + rect.size.height / 2);
218 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
219 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
220 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
221 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
222 moveGeometryDisplayCentered(scr, x + w / 2, y + h / 2);
223 }
224 WMMapWidget(scr->gview);
225 WSetGeometryViewShownPosition(scr->gview, x, y);
226 }
227
228 static void showGeometry(WWindow * wwin, int x1, int y1, int x2, int y2, int direction)
229 {
230 WScreen *scr = wwin->screen_ptr;
231 Window root = scr->root_win;
232 GC gc = scr->line_gc;
233 int ty, by, my, x, y, mx, s;
234 char num[16];
235 XSegment segment[4];
236 int fw, fh;
237
238 /* This seems necessary for some odd reason (too lazy to write x1-1 and
239 * x2-1 everywhere below in the code). But why only for x? */
240 x1--;
241 x2--;
242
243 if (HAS_BORDER_WITH_SELECT(wwin)) {
244 x1 += FRAME_BORDER_WIDTH;
245 x2 += FRAME_BORDER_WIDTH;
246 y1 += FRAME_BORDER_WIDTH;
247 y2 += FRAME_BORDER_WIDTH;
248 }
249
250 ty = y1 + wwin->frame->top_width;
251 by = y2 - wwin->frame->bottom_width;
252
253 if (wPreferences.size_display == WDIS_NEW) {
254 fw = XTextWidth(scr->tech_draw_font, "8888", 4);
255 fh = scr->tech_draw_font->ascent + scr->tech_draw_font->descent;
256
257 XSetForeground(dpy, gc, scr->line_pixel);
258
259 /* vertical geometry */
260 if (((direction & LEFT) && (x2 < scr->scr_width - fw)) || (x1 < fw)) {
261 x = x2;
262 s = -15;
263 } else {
264 x = x1;
265 s = 15;
266 }
267 my = (ty + by) / 2;
268
269 /* top arrow & end bar */
270 segment[0].x1 = x - (s + 6);
271 segment[0].y1 = ty;
272 segment[0].x2 = x - (s - 10);
273 segment[0].y2 = ty;
274
275 /* arrowhead */
276 segment[1].x1 = x - (s - 2);
277 segment[1].y1 = ty + 1;
278 segment[1].x2 = x - (s - 5);
279 segment[1].y2 = ty + 7;
280
281 segment[2].x1 = x - (s - 2);
282 segment[2].y1 = ty + 1;
283 segment[2].x2 = x - (s + 1);
284 segment[2].y2 = ty + 7;
285
286 /* line */
287 segment[3].x1 = x - (s - 2);
288 segment[3].y1 = ty + 1;
289 segment[3].x2 = x - (s - 2);
290 segment[3].y2 = my - fh / 2 - 1;
291
292 XDrawSegments(dpy, root, gc, segment, 4);
293
294 /* bottom arrow & end bar */
295 segment[0].y1 = by;
296 segment[0].y2 = by;
297
298 /* arrowhead */
299 segment[1].y1 = by - 1;
300 segment[1].y2 = by - 7;
301
302 segment[2].y1 = by - 1;
303 segment[2].y2 = by - 7;
304
305 /* line */
306 segment[3].y1 = my + fh / 2 + 2;
307 segment[3].y2 = by - 1;
308
309 XDrawSegments(dpy, root, gc, segment, 4);
310
311 snprintf(num, sizeof(num), "%i", (by - ty - wwin->normal_hints->base_height) /
312 wwin->normal_hints->height_inc);
313 fw = XTextWidth(scr->tech_draw_font, num, strlen(num));
314
315 /* Display the height. */
316 XSetFont(dpy, gc, scr->tech_draw_font->fid);
317 XDrawString(dpy, root, gc, x - s + 3 - fw / 2, my + scr->tech_draw_font->ascent - fh / 2 + 1, num,
318 strlen(num));
319
320 /* horizontal geometry */
321 if (y1 < 15) {
322 y = y2;
323 s = -15;
324 } else {
325 y = y1;
326 s = 15;
327 }
328 mx = x1 + (x2 - x1) / 2;
329 snprintf(num, sizeof(num), "%i", (x2 - x1 - wwin->normal_hints->base_width) /
330 wwin->normal_hints->width_inc);
331 fw = XTextWidth(scr->tech_draw_font, num, strlen(num));
332
333 /* left arrow & end bar */
334 segment[0].x1 = x1;
335 segment[0].y1 = y - (s + 6);
336 segment[0].x2 = x1;
337 segment[0].y2 = y - (s - 10);
338
339 /* arrowhead */
340 segment[1].x1 = x1 + 7;
341 segment[1].y1 = y - (s + 1);
342 segment[1].x2 = x1 + 1;
343 segment[1].y2 = y - (s - 2);
344
345 segment[2].x1 = x1 + 1;
346 segment[2].y1 = y - (s - 2);
347 segment[2].x2 = x1 + 7;
348 segment[2].y2 = y - (s - 5);
349
350 /* line */
351 segment[3].x1 = x1 + 1;
352 segment[3].y1 = y - (s - 2);
353 segment[3].x2 = mx - fw / 2 - 2;
354 segment[3].y2 = y - (s - 2);
355
356 XDrawSegments(dpy, root, gc, segment, 4);
357
358 /* right arrow & end bar */
359 segment[0].x1 = x2 + 1;
360 segment[0].x2 = x2 + 1;
361
362 /* arrowhead */
363 segment[1].x1 = x2 - 6;
364 segment[1].x2 = x2;
365
366 segment[2].x1 = x2;
367 segment[2].x2 = x2 - 6;
368
369 /* line */
370 segment[3].x1 = mx + fw / 2 + 2;
371 segment[3].x2 = x2;
372
373 XDrawSegments(dpy, root, gc, segment, 4);
374
375 /* Display the width. */
376 XDrawString(dpy, root, gc, mx - fw / 2 + 1, y - s + scr->tech_draw_font->ascent - fh / 2 + 1, num,
377 strlen(num));
378 } else {
379 WSetGeometryViewShownSize(scr->gview, (x2 - x1 - wwin->normal_hints->base_width)
380 / wwin->normal_hints->width_inc,
381 (by - ty - wwin->normal_hints->base_height)
382 / wwin->normal_hints->height_inc);
383 }
384 }
385
386 static void cycleGeometryDisplay(WWindow * wwin, int x, int y, int w, int h, int dir)
387 {
388 WScreen *scr = wwin->screen_ptr;
389 WMRect rect;
390
391 wPreferences.size_display++;
392 wPreferences.size_display %= NUM_DISPLAYS;
393
394 if (wPreferences.size_display == WDIS_NEW || wPreferences.size_display == WDIS_NONE) {
395 WMUnmapWidget(scr->gview);
396 } else {
397 if (wPreferences.size_display == WDIS_CENTER) {
398 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
399 moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width / 2,
400 rect.pos.y + rect.size.height / 2);
401 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
402 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
403 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
404 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
405 moveGeometryDisplayCentered(scr, x + w / 2, y + h / 2);
406 }
407 WMMapWidget(scr->gview);
408 showGeometry(wwin, x, y, x + w, y + h, dir);
409 }
410 }
411
412 static void mapGeometryDisplay(WWindow * wwin, int x, int y, int w, int h)
413 {
414 WScreen *scr = wwin->screen_ptr;
415 WMRect rect;
416
417 if (wPreferences.size_display == WDIS_NEW || wPreferences.size_display == WDIS_NONE)
418 return;
419
420 if (wPreferences.size_display == WDIS_CENTER) {
421 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
422 moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width / 2,
423 rect.pos.y + rect.size.height / 2);
424 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
425 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
426 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
427 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
428 moveGeometryDisplayCentered(scr, x + w / 2, y + h / 2);
429 }
430 WMMapWidget(scr->gview);
431 showGeometry(wwin, x, y, x + w, y + h, 0);
432 }
433
434 static void doWindowMove(WWindow * wwin, WMArray * array, int dx, int dy)
435 {
436 WWindow *tmpw;
437 WScreen *scr = wwin->screen_ptr;
438 int x, y;
439
440 if (!array || !WMGetArrayItemCount(array)) {
441 wWindowMove(wwin, wwin->frame_x + dx, wwin->frame_y + dy);
442 } else {
443 WMArrayIterator iter;
444
445 WM_ITERATE_ARRAY(array, tmpw, iter) {
446 x = tmpw->frame_x + dx;
447 y = tmpw->frame_y + dy;
448
449 #if 1 /* XXX: with xinerama patch was #if 0, check this */
450 /* don't let windows become unreachable */
451
452 if (x + (int)tmpw->frame->core->width < 20)
453 x = 20 - (int)tmpw->frame->core->width;
454 else if (x + 20 > scr->scr_width)
455 x = scr->scr_width - 20;
456
457 if (y + (int)tmpw->frame->core->height < 20)
458 y = 20 - (int)tmpw->frame->core->height;
459 else if (y + 20 > scr->scr_height)
460 y = scr->scr_height - 20;
461 #else
462 wScreenBringInside(scr, &x, &y,
463 (int)tmpw->frame->core->width, (int)tmpw->frame->core->height);
464 #endif
465
466 wWindowMove(tmpw, x, y);
467 }
468 }
469 }
470
471 static void drawTransparentFrame(WWindow * wwin, int x, int y, int width, int height)
472 {
473 Window root = wwin->screen_ptr->root_win;
474 GC gc = wwin->screen_ptr->frame_gc;
475 int h = 0;
476 int bottom = 0;
477
478 if (HAS_BORDER_WITH_SELECT(wwin)) {
479 x += FRAME_BORDER_WIDTH;
480 y += FRAME_BORDER_WIDTH;
481 }
482
483 if (HAS_TITLEBAR(wwin) && !wwin->flags.shaded) {
484 h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance +
485 TITLEBAR_EXTEND_SPACE) * 2;
486 }
487 if (HAS_RESIZEBAR(wwin) && !wwin->flags.shaded) {
488 /* Can't use wwin-frame->bottom_width because, in some cases
489 (e.g. interactive placement), frame does not point to anything. */
490 bottom = RESIZEBAR_HEIGHT;
491 }
492 XDrawRectangle(dpy, root, gc, x - 1, y - 1, width + 1, height + 1);
493
494 if (h > 0) {
495 XDrawLine(dpy, root, gc, x, y + h - 1, x + width, y + h - 1);
496 }
497 if (bottom > 0) {
498 XDrawLine(dpy, root, gc, x, y + height - bottom, x + width, y + height - bottom);
499 }
500 }
501
502 static void drawFrames(WWindow * wwin, WMArray * array, int dx, int dy)
503 {
504 WWindow *tmpw;
505 int scr_width = wwin->screen_ptr->scr_width;
506 int scr_height = wwin->screen_ptr->scr_height;
507 int x, y;
508
509 if (!array) {
510
511 x = wwin->frame_x + dx;
512 y = wwin->frame_y + dy;
513
514 drawTransparentFrame(wwin, x, y, wwin->frame->core->width, wwin->frame->core->height);
515
516 } else {
517 WMArrayIterator iter;
518
519 WM_ITERATE_ARRAY(array, tmpw, iter) {
520 x = tmpw->frame_x + dx;
521 y = tmpw->frame_y + dy;
522
523 /* don't let windows become unreachable */
524 #if 1 /* XXX: was 0 in XINERAMA patch, check */
525 if (x + (int)tmpw->frame->core->width < 20)
526 x = 20 - (int)tmpw->frame->core->width;
527 else if (x + 20 > scr_width)
528 x = scr_width - 20;
529
530 if (y + (int)tmpw->frame->core->height < 20)
531 y = 20 - (int)tmpw->frame->core->height;
532 else if (y + 20 > scr_height)
533 y = scr_height - 20;
534
535 #else
536 wScreenBringInside(wwin->screen_ptr, &x, &y,
537 (int)tmpw->frame->core->width, (int)tmpw->frame->core->height);
538 #endif
539
540 drawTransparentFrame(tmpw, x, y, tmpw->frame->core->width, tmpw->frame->core->height);
541 }
542 }
543 }
544
545 static void flushMotion()
546 {
547 XEvent ev;
548
549 XSync(dpy, False);
550 while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
551 }
552
553 static void crossWorkspace(WScreen * scr, WWindow * wwin, int opaque_move, int new_workspace, int rewind)
554 {
555 /* do not let window be unmapped */
556 if (opaque_move) {
557 wwin->flags.changing_workspace = 1;
558 wWindowChangeWorkspace(wwin, new_workspace);
559 }
560 /* go to new workspace */
561 wWorkspaceChange(scr, new_workspace);
562
563 wwin->flags.changing_workspace = 0;
564
565 if (rewind)
566 XWarpPointer(dpy, None, None, 0, 0, 0, 0, scr->scr_width - 20, 0);
567 else
568 XWarpPointer(dpy, None, None, 0, 0, 0, 0, -(scr->scr_width - 20), 0);
569
570 flushMotion();
571
572 if (!opaque_move) {
573 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
574 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
575 GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
576 }
577 }
578
579 typedef struct {
580 /* arrays of WWindows sorted by the respective border position */
581 WWindow **topList; /* top border */
582 WWindow **leftList; /* left border */
583 WWindow **rightList; /* right border */
584 WWindow **bottomList; /* bottom border */
585 int count;
586
587 /* index of window in the above lists indicating the relative position
588 * of the window with the others */
589 int topIndex;
590 int leftIndex;
591 int rightIndex;
592 int bottomIndex;
593
594 int rubCount; /* for workspace switching */
595
596 int winWidth, winHeight; /* width/height of the window */
597 int realX, realY; /* actual position of the window */
598 int calcX, calcY; /* calculated position of window */
599 int omouseX, omouseY; /* old mouse position */
600 int mouseX, mouseY; /* last known position of the pointer */
601 } MoveData;
602
603 #define WTOP(w) (w)->frame_y
604 #define WLEFT(w) (w)->frame_x
605 #define WRIGHT(w) ((w)->frame_x + (int)(w)->frame->core->width - 1 + \
606 (HAS_BORDER_WITH_SELECT(w) ? 2*FRAME_BORDER_WIDTH : 0))
607 #define WBOTTOM(w) ((w)->frame_y + (int)(w)->frame->core->height - 1 + \
608 (HAS_BORDER_WITH_SELECT(w) ? 2*FRAME_BORDER_WIDTH : 0))
609
610 static int compareWTop(const void *a, const void *b)
611 {
612 WWindow *wwin1 = *(WWindow **) a;
613 WWindow *wwin2 = *(WWindow **) b;
614
615 if (WTOP(wwin1) > WTOP(wwin2))
616 return -1;
617 else if (WTOP(wwin1) < WTOP(wwin2))
618 return 1;
619 else
620 return 0;
621 }
622
623 static int compareWLeft(const void *a, const void *b)
624 {
625 WWindow *wwin1 = *(WWindow **) a;
626 WWindow *wwin2 = *(WWindow **) b;
627
628 if (WLEFT(wwin1) > WLEFT(wwin2))
629 return -1;
630 else if (WLEFT(wwin1) < WLEFT(wwin2))
631 return 1;
632 else
633 return 0;
634 }
635
636 static int compareWRight(const void *a, const void *b)
637 {
638 WWindow *wwin1 = *(WWindow **) a;
639 WWindow *wwin2 = *(WWindow **) b;
640
641 if (WRIGHT(wwin1) < WRIGHT(wwin2))
642 return -1;
643 else if (WRIGHT(wwin1) > WRIGHT(wwin2))
644 return 1;
645 else
646 return 0;
647 }
648
649 static int compareWBottom(const void *a, const void *b)
650 {
651 WWindow *wwin1 = *(WWindow **) a;
652 WWindow *wwin2 = *(WWindow **) b;
653
654 if (WBOTTOM(wwin1) < WBOTTOM(wwin2))
655 return -1;
656 else if (WBOTTOM(wwin1) > WBOTTOM(wwin2))
657 return 1;
658 else
659 return 0;
660 }
661
662 static void updateResistance(WWindow * wwin, MoveData * data, int newX, int newY)
663 {
664 int i;
665 int newX2 = newX + data->winWidth;
666 int newY2 = newY + data->winHeight;
667 Bool ok = False;
668
669 if (newX < data->realX) {
670 if (data->rightIndex > 0 && newX < WRIGHT(data->rightList[data->rightIndex - 1])) {
671 ok = True;
672 } else if (data->leftIndex <= data->count - 1 && newX2 <= WLEFT(data->leftList[data->leftIndex])) {
673 ok = True;
674 }
675 } else if (newX > data->realX) {
676 if (data->leftIndex > 0 && newX2 > WLEFT(data->leftList[data->leftIndex - 1])) {
677 ok = True;
678 } else if (data->rightIndex <= data->count - 1
679 && newX >= WRIGHT(data->rightList[data->rightIndex])) {
680 ok = True;
681 }
682 }
683
684 if (!ok) {
685 if (newY < data->realY) {
686 if (data->bottomIndex > 0 && newY < WBOTTOM(data->bottomList[data->bottomIndex - 1])) {
687 ok = True;
688 } else if (data->topIndex <= data->count - 1
689 && newY2 <= WTOP(data->topList[data->topIndex])) {
690 ok = True;
691 }
692 } else if (newY > data->realY) {
693 if (data->topIndex > 0 && newY2 > WTOP(data->topList[data->topIndex - 1])) {
694 ok = True;
695 } else if (data->bottomIndex <= data->count - 1
696 && newY >= WBOTTOM(data->bottomList[data->bottomIndex])) {
697 ok = True;
698 }
699 }
700 }
701
702 if (!ok)
703 return;
704
705 /* TODO: optimize this */
706 if (data->realY < WBOTTOM(data->bottomList[0])) {
707 data->bottomIndex = 0;
708 }
709 if (data->realX < WRIGHT(data->rightList[0])) {
710 data->rightIndex = 0;
711 }
712 if ((data->realX + data->winWidth) > WLEFT(data->leftList[0])) {
713 data->leftIndex = 0;
714 }
715 if ((data->realY + data->winHeight) > WTOP(data->topList[0])) {
716 data->topIndex = 0;
717 }
718 for (i = 0; i < data->count; i++) {
719 if (data->realY > WBOTTOM(data->bottomList[i])) {
720 data->bottomIndex = i + 1;
721 }
722 if (data->realX > WRIGHT(data->rightList[i])) {
723 data->rightIndex = i + 1;
724 }
725 if ((data->realX + data->winWidth) < WLEFT(data->leftList[i])) {
726 data->leftIndex = i + 1;
727 }
728 if ((data->realY + data->winHeight) < WTOP(data->topList[i])) {
729 data->topIndex = i + 1;
730 }
731 }
732 }
733
734 static void freeMoveData(MoveData * data)
735 {
736 if (data->topList)
737 wfree(data->topList);
738 if (data->leftList)
739 wfree(data->leftList);
740 if (data->rightList)
741 wfree(data->rightList);
742 if (data->bottomList)
743 wfree(data->bottomList);
744 }
745
746 static void updateMoveData(WWindow * wwin, MoveData * data)
747 {
748 WScreen *scr = wwin->screen_ptr;
749 WWindow *tmp;
750 int i;
751
752 data->count = 0;
753 tmp = scr->focused_window;
754 while (tmp) {
755 if (tmp != wwin && scr->current_workspace == tmp->frame->workspace
756 && !tmp->flags.miniaturized
757 && !tmp->flags.hidden && !tmp->flags.obscured && !WFLAGP(tmp, sunken)) {
758 data->topList[data->count] = tmp;
759 data->leftList[data->count] = tmp;
760 data->rightList[data->count] = tmp;
761 data->bottomList[data->count] = tmp;
762 data->count++;
763 }
764 tmp = tmp->prev;
765 }
766
767 if (data->count == 0) {
768 data->topIndex = 0;
769 data->leftIndex = 0;
770 data->rightIndex = 0;
771 data->bottomIndex = 0;
772 return;
773 }
774
775 /* order from closest to the border of the screen to farthest */
776
777 qsort(data->topList, data->count, sizeof(WWindow **), compareWTop);
778 qsort(data->leftList, data->count, sizeof(WWindow **), compareWLeft);
779 qsort(data->rightList, data->count, sizeof(WWindow **), compareWRight);
780 qsort(data->bottomList, data->count, sizeof(WWindow **), compareWBottom);
781
782 /* figure the position of the window relative to the others */
783
784 data->topIndex = -1;
785 data->leftIndex = -1;
786 data->rightIndex = -1;
787 data->bottomIndex = -1;
788
789 if (WTOP(wwin) < WBOTTOM(data->bottomList[0])) {
790 data->bottomIndex = 0;
791 }
792 if (WLEFT(wwin) < WRIGHT(data->rightList[0])) {
793 data->rightIndex = 0;
794 }
795 if (WRIGHT(wwin) > WLEFT(data->leftList[0])) {
796 data->leftIndex = 0;
797 }
798 if (WBOTTOM(wwin) > WTOP(data->topList[0])) {
799 data->topIndex = 0;
800 }
801 for (i = 0; i < data->count; i++) {
802 if (WTOP(wwin) >= WBOTTOM(data->bottomList[i])) {
803 data->bottomIndex = i + 1;
804 }
805 if (WLEFT(wwin) >= WRIGHT(data->rightList[i])) {
806 data->rightIndex = i + 1;
807 }
808 if (WRIGHT(wwin) <= WLEFT(data->leftList[i])) {
809 data->leftIndex = i + 1;
810 }
811 if (WBOTTOM(wwin) <= WTOP(data->topList[i])) {
812 data->topIndex = i + 1;
813 }
814 }
815 }
816
817 static void initMoveData(WWindow * wwin, MoveData * data)
818 {
819 int i;
820 WWindow *tmp;
821
822 memset(data, 0, sizeof(MoveData));
823
824 for (i = 0, tmp = wwin->screen_ptr->focused_window; tmp != NULL; tmp = tmp->prev, i++) ;
825
826 if (i > 1) {
827 data->topList = wmalloc(sizeof(WWindow *) * i);
828 data->leftList = wmalloc(sizeof(WWindow *) * i);
829 data->rightList = wmalloc(sizeof(WWindow *) * i);
830 data->bottomList = wmalloc(sizeof(WWindow *) * i);
831
832 updateMoveData(wwin, data);
833 }
834
835 data->realX = wwin->frame_x;
836 data->realY = wwin->frame_y;
837 data->calcX = wwin->frame_x;
838 data->calcY = wwin->frame_y;
839
840 data->winWidth = wwin->frame->core->width + (HAS_BORDER_WITH_SELECT(wwin) ? 2 * FRAME_BORDER_WIDTH : 0);
841 data->winHeight = wwin->frame->core->height + (HAS_BORDER_WITH_SELECT(wwin) ? 2 * FRAME_BORDER_WIDTH : 0);
842 }
843
844 static Bool checkWorkspaceChange(WWindow * wwin, MoveData * data, Bool opaqueMove)
845 {
846 WScreen *scr = wwin->screen_ptr;
847 Bool changed = False;
848
849 if (data->mouseX <= 1) {
850 if (scr->current_workspace > 0) {
851
852 crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace - 1, True);
853 changed = True;
854 data->rubCount = 0;
855
856 } else if (scr->current_workspace == 0 && wPreferences.ws_cycle) {
857
858 crossWorkspace(scr, wwin, opaqueMove, scr->workspace_count - 1, True);
859 changed = True;
860 data->rubCount = 0;
861 }
862 } else if (data->mouseX >= scr->scr_width - 2) {
863
864 if (scr->current_workspace == scr->workspace_count - 1) {
865
866 if (wPreferences.ws_cycle || scr->workspace_count == MAX_WORKSPACES) {
867
868 crossWorkspace(scr, wwin, opaqueMove, 0, False);
869 changed = True;
870 data->rubCount = 0;
871 }
872 /* if user insists on trying to go to next workspace even when
873 * it's already the last, create a new one */
874 else if (data->omouseX == data->mouseX && wPreferences.ws_advance) {
875
876 /* detect user "rubbing" the window against the edge */
877 if (data->rubCount > 0 && data->omouseY - data->mouseY > MOVE_THRESHOLD) {
878
879 data->rubCount = -(data->rubCount + 1);
880
881 } else if (data->rubCount <= 0 && data->mouseY - data->omouseY > MOVE_THRESHOLD) {
882
883 data->rubCount = -data->rubCount + 1;
884 }
885 }
886 /* create a new workspace */
887 if (abs(data->rubCount) > 2) {
888 /* go to next workspace */
889 wWorkspaceNew(scr);
890
891 crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace + 1, False);
892 changed = True;
893 data->rubCount = 0;
894 }
895 } else if (scr->current_workspace < scr->workspace_count) {
896
897 /* go to next workspace */
898 crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace + 1, False);
899 changed = True;
900 data->rubCount = 0;
901 }
902 } else {
903 data->rubCount = 0;
904 }
905
906 return changed;
907 }
908
909 static void
910 updateWindowPosition(WWindow * wwin, MoveData * data, Bool doResistance,
911 Bool opaqueMove, int newMouseX, int newMouseY)
912 {
913 WScreen *scr = wwin->screen_ptr;
914 int dx, dy; /* how much mouse moved */
915 int winL, winR, winT, winB; /* requested new window position */
916 int newX, newY; /* actual new window position */
917 Bool hresist, vresist;
918 Bool updateIndex;
919 Bool attract;
920
921 hresist = False;
922 vresist = False;
923
924 updateIndex = False;
925
926 /* check the direction of the movement */
927 dx = newMouseX - data->mouseX;
928 dy = newMouseY - data->mouseY;
929
930 data->omouseX = data->mouseX;
931 data->omouseY = data->mouseY;
932 data->mouseX = newMouseX;
933 data->mouseY = newMouseY;
934
935 winL = data->calcX + dx;
936 winR = data->calcX + data->winWidth + dx;
937 winT = data->calcY + dy;
938 winB = data->calcY + data->winHeight + dy;
939
940 newX = data->realX;
941 newY = data->realY;
942
943 if (doResistance) {
944 int l_edge, r_edge;
945 int edge_l, edge_r;
946 int t_edge, b_edge;
947 int edge_t, edge_b;
948 int resist;
949
950 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
951 attract = wPreferences.attract;
952 /* horizontal movement: check horizontal edge resistances */
953 if (dx || dy) {
954 WMRect rect;
955 int i, head;
956 /* window is the leftmost window: check against screen edge */
957
958 /* Add inter head resistance 1/2 (if needed) */
959 head = wGetHeadForPointerLocation(scr);
960 rect = wGetRectForHead(scr, head);
961
962 l_edge = WMAX(scr->totalUsableArea[head].x1, rect.pos.x);
963 edge_l = l_edge - resist;
964 edge_r = WMIN(scr->totalUsableArea[head].x2, rect.pos.x + rect.size.width);
965 r_edge = edge_r + resist;
966
967 /* 1 */
968 if ((data->rightIndex >= 0) && (data->rightIndex <= data->count)) {
969 WWindow *looprw;
970
971 for (i = data->rightIndex - 1; i >= 0; i--) {
972 looprw = data->rightList[i];
973 if (!(data->realY > WBOTTOM(looprw)
974 || (data->realY + data->winHeight) < WTOP(looprw))) {
975 if (attract || ((data->realX < (WRIGHT(looprw) + 2)) && dx < 0)) {
976 l_edge = WRIGHT(looprw) + 1;
977 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
978 }
979 break;
980 }
981 }
982
983 if (attract) {
984 for (i = data->rightIndex; i < data->count; i++) {
985 looprw = data->rightList[i];
986 if (!(data->realY > WBOTTOM(looprw)
987 || (data->realY + data->winHeight) < WTOP(looprw))) {
988 r_edge = WRIGHT(looprw) + 1;
989 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
990 break;
991 }
992 }
993 }
994 }
995
996 if ((data->leftIndex >= 0) && (data->leftIndex <= data->count)) {
997 WWindow *looprw;
998
999 for (i = data->leftIndex - 1; i >= 0; i--) {
1000 looprw = data->leftList[i];
1001 if (!(data->realY > WBOTTOM(looprw)
1002 || (data->realY + data->winHeight) < WTOP(looprw))) {
1003 if (attract
1004 || (((data->realX + data->winWidth) > (WLEFT(looprw) - 1))
1005 && dx > 0)) {
1006 edge_r = WLEFT(looprw);
1007 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1008 }
1009 break;
1010 }
1011 }
1012
1013 if (attract)
1014 for (i = data->leftIndex; i < data->count; i++) {
1015 looprw = data->leftList[i];
1016 if (!(data->realY > WBOTTOM(looprw)
1017 || (data->realY + data->winHeight) < WTOP(looprw))) {
1018 edge_l = WLEFT(looprw);
1019 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1020 break;
1021 }
1022 }
1023 }
1024
1025 /*
1026 printf("%d %d\n",winL,winR);
1027 printf("l_ %d r_ %d _l %d _r %d\n",l_edge,r_edge,edge_l,edge_r);
1028 */
1029
1030 if ((winL - l_edge) < (r_edge - winL)) {
1031 if (resist > 0) {
1032 if ((attract && winL <= l_edge + resist && winL >= l_edge - resist)
1033 || (dx < 0 && winL <= l_edge && winL >= l_edge - resist)) {
1034 newX = l_edge;
1035 hresist = True;
1036 }
1037 }
1038 } else {
1039 if (resist > 0 && attract && winL >= r_edge - resist && winL <= r_edge + resist) {
1040 newX = r_edge;
1041 hresist = True;
1042 }
1043 }
1044
1045 if ((winR - edge_l) < (edge_r - winR)) {
1046 if (resist > 0 && attract && winR <= edge_l + resist && winR >= edge_l - resist) {
1047 newX = edge_l - data->winWidth;
1048 hresist = True;
1049 }
1050 } else {
1051 if (resist > 0) {
1052 if ((attract && winR >= edge_r - resist && winR <= edge_r + resist)
1053 || (dx > 0 && winR >= edge_r && winR <= edge_r + resist)) {
1054 newX = edge_r - data->winWidth;
1055 hresist = True;
1056 }
1057 }
1058 }
1059
1060 /* VeRT */
1061 /* Add inter head resistance 2/2 (if needed) */
1062 t_edge = WMAX(scr->totalUsableArea[head].y1, rect.pos.y);
1063 edge_t = t_edge - resist;
1064 edge_b = WMIN(scr->totalUsableArea[head].y2, rect.pos.y + rect.size.height);
1065 b_edge = edge_b + resist;
1066
1067 if ((data->bottomIndex >= 0) && (data->bottomIndex <= data->count)) {
1068 WWindow *looprw;
1069
1070 for (i = data->bottomIndex - 1; i >= 0; i--) {
1071 looprw = data->bottomList[i];
1072 if (!(data->realX > WRIGHT(looprw)
1073 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1074 if (attract || ((data->realY < (WBOTTOM(looprw) + 2)) && dy < 0)) {
1075 t_edge = WBOTTOM(looprw) + 1;
1076 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1077 }
1078 break;
1079 }
1080 }
1081
1082 if (attract) {
1083 for (i = data->bottomIndex; i < data->count; i++) {
1084 looprw = data->bottomList[i];
1085 if (!(data->realX > WRIGHT(looprw)
1086 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1087 b_edge = WBOTTOM(looprw) + 1;
1088 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1089 break;
1090 }
1091 }
1092 }
1093 }
1094
1095 if ((data->topIndex >= 0) && (data->topIndex <= data->count)) {
1096 WWindow *looprw;
1097
1098 for (i = data->topIndex - 1; i >= 0; i--) {
1099 looprw = data->topList[i];
1100 if (!(data->realX > WRIGHT(looprw)
1101 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1102 if (attract
1103 || (((data->realY + data->winHeight) > (WTOP(looprw) - 1))
1104 && dy > 0)) {
1105 edge_b = WTOP(looprw);
1106 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1107 }
1108 break;
1109 }
1110 }
1111
1112 if (attract)
1113 for (i = data->topIndex; i < data->count; i++) {
1114 looprw = data->topList[i];
1115 if (!(data->realX > WRIGHT(looprw)
1116 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1117 edge_t = WTOP(looprw);
1118 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1119 break;
1120 }
1121 }
1122 }
1123
1124 if ((winT - t_edge) < (b_edge - winT)) {
1125 if (resist > 0) {
1126 if ((attract && winT <= t_edge + resist && winT >= t_edge - resist)
1127 || (dy < 0 && winT <= t_edge && winT >= t_edge - resist)) {
1128 newY = t_edge;
1129 vresist = True;
1130 }
1131 }
1132 } else {
1133 if (resist > 0 && attract && winT >= b_edge - resist && winT <= b_edge + resist) {
1134 newY = b_edge;
1135 vresist = True;
1136 }
1137 }
1138
1139 if ((winB - edge_t) < (edge_b - winB)) {
1140 if (resist > 0 && attract && winB <= edge_t + resist && winB >= edge_t - resist) {
1141 newY = edge_t - data->winHeight;
1142 vresist = True;
1143 }
1144 } else {
1145 if (resist > 0) {
1146 if ((attract && winB >= edge_b - resist && winB <= edge_b + resist)
1147 || (dy > 0 && winB >= edge_b && winB <= edge_b + resist)) {
1148 newY = edge_b - data->winHeight;
1149 vresist = True;
1150 }
1151 }
1152 }
1153 }
1154 /* END VeRT */
1155
1156 }
1157
1158 /* update window position */
1159 data->calcX += dx;
1160 data->calcY += dy;
1161
1162 if (((dx > 0 && data->calcX - data->realX > 0)
1163 || (dx < 0 && data->calcX - data->realX < 0)) && !hresist)
1164 newX = data->calcX;
1165
1166 if (((dy > 0 && data->calcY - data->realY > 0)
1167 || (dy < 0 && data->calcY - data->realY < 0)) && !vresist)
1168 newY = data->calcY;
1169
1170 if (data->realX != newX || data->realY != newY) {
1171
1172 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1173 showPosition(wwin, data->realX, data->realY);
1174 }
1175 if (opaqueMove) {
1176 doWindowMove(wwin, scr->selected_windows, newX - wwin->frame_x, newY - wwin->frame_y);
1177 } else {
1178 /* erase frames */
1179 drawFrames(wwin, scr->selected_windows,
1180 data->realX - wwin->frame_x, data->realY - wwin->frame_y);
1181 }
1182
1183 if (!scr->selected_windows && wPreferences.move_display == WDIS_FRAME_CENTER) {
1184
1185 moveGeometryDisplayCentered(scr, newX + data->winWidth / 2, newY + data->winHeight / 2);
1186 }
1187
1188 if (!opaqueMove) {
1189 /* draw frames */
1190 drawFrames(wwin, scr->selected_windows, newX - wwin->frame_x, newY - wwin->frame_y);
1191 }
1192
1193 if (!scr->selected_windows) {
1194 showPosition(wwin, newX, newY);
1195 }
1196 }
1197
1198 /* recalc relative window position */
1199 if (doResistance && (data->realX != newX || data->realY != newY)) {
1200 updateResistance(wwin, data, newX, newY);
1201 }
1202
1203 data->realX = newX;
1204 data->realY = newY;
1205 }
1206
1207 #define _KS KEY_CONTROL_WINDOW_WEIGHT
1208
1209 #define MOVABLE_BIT 0x01
1210 #define RESIZABLE_BIT 0x02
1211
1212 int wKeyboardMoveResizeWindow(WWindow * wwin)
1213 {
1214 WScreen *scr = wwin->screen_ptr;
1215 Window root = scr->root_win;
1216 XEvent event;
1217 int w = wwin->frame->core->width;
1218 int h = wwin->frame->core->height;
1219 int scr_width = wwin->screen_ptr->scr_width;
1220 int scr_height = wwin->screen_ptr->scr_height;
1221 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1222 int src_x = wwin->frame_x;
1223 int src_y = wwin->frame_y;
1224 int done, off_x, off_y, ww, wh;
1225 int kspeed = _KS;
1226 Time lastTime = 0;
1227 KeyCode shiftl, shiftr, ctrll, ctrlmode;
1228 KeySym keysym = NoSymbol;
1229 int moment = 0;
1230 int modes = ((IS_MOVABLE(wwin) ? MOVABLE_BIT : 0) | (IS_RESIZABLE(wwin) ? RESIZABLE_BIT : 0));
1231 int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1)
1232 ? wGetHeadForWindow(wwin)
1233 : scr->xine_info.primary_head);
1234
1235 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1236 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1237 ctrll = XKeysymToKeycode(dpy, XK_Control_L);
1238 ctrlmode = done = off_x = off_y = 0;
1239
1240 if (modes == RESIZABLE_BIT) {
1241 ctrlmode = 1;
1242 }
1243
1244 XSync(dpy, False);
1245 wusleep(10000);
1246 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1247
1248 if (!wwin->flags.selected) {
1249 wUnselectWindows(scr);
1250 }
1251 XGrabServer(dpy);
1252 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
1253 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
1254 GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime);
1255
1256 if (wwin->flags.shaded || scr->selected_windows) {
1257 if (scr->selected_windows)
1258 drawFrames(wwin, scr->selected_windows, off_x, off_y);
1259 else
1260 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, w, h);
1261 if (!scr->selected_windows)
1262 mapPositionDisplay(wwin, src_x, src_y, w, h);
1263 } else {
1264 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, w, h);
1265 }
1266 ww = w;
1267 wh = h;
1268 while (1) {
1269 /*
1270 looper.ox=off_x;
1271 looper.oy=off_y;
1272 */
1273 do {
1274 WMMaskEvent(dpy, KeyPressMask | ButtonReleaseMask
1275 | ButtonPressMask | ExposureMask, &event);
1276 if (event.type == Expose) {
1277 WMHandleEvent(&event);
1278 }
1279 } while (event.type == Expose);
1280
1281 if (wwin->flags.shaded || scr->selected_windows) {
1282 if (scr->selected_windows)
1283 drawFrames(wwin, scr->selected_windows, off_x, off_y);
1284 else
1285 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, w, h);
1286 /*** I HATE EDGE RESISTANCE - ]d ***/
1287 } else {
1288 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, ww, wh);
1289 }
1290
1291 if (ctrlmode)
1292 showGeometry(wwin, src_x + off_x, src_y + off_y, src_x + off_x + ww, src_y + off_y + wh,
1293 0);
1294
1295 XUngrabServer(dpy);
1296 XSync(dpy, False);
1297
1298 switch (event.type) {
1299 case KeyPress:
1300 /* accelerate */
1301 if (event.xkey.time - lastTime > 50) {
1302 kspeed /= (1 + (event.xkey.time - lastTime) / 100);
1303 } else {
1304 if (kspeed < 20) {
1305 kspeed++;
1306 }
1307 }
1308 if (kspeed < _KS)
1309 kspeed = _KS;
1310 lastTime = event.xkey.time;
1311 if (modes == (MOVABLE_BIT | RESIZABLE_BIT)) {
1312 if ((event.xkey.state & ControlMask) && !wwin->flags.shaded) {
1313 ctrlmode = 1;
1314 wUnselectWindows(scr);
1315 } else {
1316 ctrlmode = 0;
1317 }
1318 }
1319 if (event.xkey.keycode == shiftl || event.xkey.keycode == shiftr) {
1320 if (ctrlmode)
1321 cycleGeometryDisplay(wwin, src_x + off_x, src_y + off_y, ww, wh, 0);
1322 else
1323 cyclePositionDisplay(wwin, src_x + off_x, src_y + off_y, ww, wh);
1324 } else {
1325
1326 keysym = XLookupKeysym(&event.xkey, 0);
1327 switch (keysym) {
1328 case XK_Return:
1329 done = 2;
1330 break;
1331 case XK_Escape:
1332 done = 1;
1333 break;
1334 case XK_Up:
1335 #ifdef XK_KP_Up
1336 case XK_KP_Up:
1337 #endif
1338 case XK_k:
1339 if (ctrlmode) {
1340 if (moment != UP)
1341 h = wh;
1342 h -= kspeed;
1343 moment = UP;
1344 if (h < 1)
1345 h = 1;
1346 } else
1347 off_y -= kspeed;
1348 break;
1349 case XK_Down:
1350 #ifdef XK_KP_Down
1351 case XK_KP_Down:
1352 #endif
1353 case XK_j:
1354 if (ctrlmode) {
1355 if (moment != DOWN)
1356 h = wh;
1357 h += kspeed;
1358 moment = DOWN;
1359 } else
1360 off_y += kspeed;
1361 break;
1362 case XK_Left:
1363 #ifdef XK_KP_Left
1364 case XK_KP_Left:
1365 #endif
1366 case XK_h:
1367 if (ctrlmode) {
1368 if (moment != LEFT)
1369 w = ww;
1370 w -= kspeed;
1371 if (w < 1)
1372 w = 1;
1373 moment = LEFT;
1374 } else
1375 off_x -= kspeed;
1376 break;
1377 case XK_Right:
1378 #ifdef XK_KP_Right
1379 case XK_KP_Right:
1380 #endif
1381 case XK_l:
1382 if (ctrlmode) {
1383 if (moment != RIGHT)
1384 w = ww;
1385 w += kspeed;
1386 moment = RIGHT;
1387 } else
1388 off_x += kspeed;
1389 break;
1390 }
1391
1392 ww = w;
1393 wh = h;
1394 wh -= vert_border;
1395 wWindowConstrainSize(wwin, (unsigned int *)&ww, (unsigned int *)&wh);
1396 wh += vert_border;
1397
1398 if (wPreferences.ws_cycle) {
1399 if (src_x + off_x + ww < 20) {
1400 if (!scr->current_workspace) {
1401 wWorkspaceChange(scr, scr->workspace_count - 1);
1402 } else
1403 wWorkspaceChange(scr, scr->current_workspace - 1);
1404 off_x += scr_width;
1405 } else if (src_x + off_x + 20 > scr_width) {
1406 if (scr->current_workspace == scr->workspace_count - 1) {
1407 wWorkspaceChange(scr, 0);
1408 } else
1409 wWorkspaceChange(scr, scr->current_workspace + 1);
1410 off_x -= scr_width;
1411 }
1412 } else {
1413 if (src_x + off_x + ww < 20)
1414 off_x = 20 - ww - src_x;
1415 else if (src_x + off_x + 20 > scr_width)
1416 off_x = scr_width - 20 - src_x;
1417 }
1418
1419 if (src_y + off_y + wh < 20) {
1420 off_y = 20 - wh - src_y;
1421 } else if (src_y + off_y + 20 > scr_height) {
1422 off_y = scr_height - 20 - src_y;
1423 }
1424 }
1425 break;
1426 case ButtonPress:
1427 case ButtonRelease:
1428 done = 1;
1429 break;
1430 case Expose:
1431 WMHandleEvent(&event);
1432 while (XCheckTypedEvent(dpy, Expose, &event)) {
1433 WMHandleEvent(&event);
1434 }
1435 break;
1436
1437 default:
1438 WMHandleEvent(&event);
1439 break;
1440 }
1441
1442 XGrabServer(dpy);
1443 /*xxx */
1444
1445 if (wwin->flags.shaded && !scr->selected_windows) {
1446 moveGeometryDisplayCentered(scr, src_x + off_x + w / 2, src_y + off_y + h / 2);
1447 } else {
1448 if (ctrlmode) {
1449 WMUnmapWidget(scr->gview);
1450 mapGeometryDisplay(wwin, src_x + off_x, src_y + off_y, ww, wh);
1451 } else if (!scr->selected_windows) {
1452 WMUnmapWidget(scr->gview);
1453 mapPositionDisplay(wwin, src_x + off_x, src_y + off_y, ww, wh);
1454 }
1455 }
1456
1457 if (wwin->flags.shaded || scr->selected_windows) {
1458 if (scr->selected_windows)
1459 drawFrames(wwin, scr->selected_windows, off_x, off_y);
1460 else
1461 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, w, h);
1462 } else {
1463 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, ww, wh);
1464 }
1465
1466 if (ctrlmode) {
1467 showGeometry(wwin, src_x + off_x, src_y + off_y, src_x + off_x + ww, src_y + off_y + wh,
1468 0);
1469 } else if (!scr->selected_windows)
1470 showPosition(wwin, src_x + off_x, src_y + off_y);
1471
1472 if (done) {
1473 scr->keymove_tick = 0;
1474 /*
1475 WMDeleteTimerWithClientData(&looper);
1476 */
1477 if (wwin->flags.shaded || scr->selected_windows) {
1478 if (scr->selected_windows)
1479 drawFrames(wwin, scr->selected_windows, off_x, off_y);
1480 else
1481 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, w, h);
1482 } else {
1483 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, ww, wh);
1484 }
1485
1486 if (ctrlmode) {
1487 showGeometry(wwin, src_x + off_x, src_y + off_y, src_x + off_x + ww,
1488 src_y + off_y + wh, 0);
1489 WMUnmapWidget(scr->gview);
1490 } else
1491 WMUnmapWidget(scr->gview);
1492
1493 XUngrabKeyboard(dpy, CurrentTime);
1494 XUngrabPointer(dpy, CurrentTime);
1495 XUngrabServer(dpy);
1496
1497 if (done == 2) {
1498 if (wwin->flags.shaded || scr->selected_windows) {
1499 if (!scr->selected_windows) {
1500 wWindowMove(wwin, src_x + off_x, src_y + off_y);
1501 wWindowSynthConfigureNotify(wwin);
1502 } else {
1503 WMArrayIterator iter;
1504 WWindow *foo;
1505
1506 doWindowMove(wwin, scr->selected_windows, off_x, off_y);
1507
1508 WM_ITERATE_ARRAY(scr->selected_windows, foo, iter) {
1509 wWindowSynthConfigureNotify(foo);
1510 }
1511 }
1512 } else {
1513 if (wwin->client.width != ww)
1514 wwin->flags.user_changed_width = 1;
1515
1516 if (wwin->client.height != wh - vert_border)
1517 wwin->flags.user_changed_height = 1;
1518
1519 wWindowConfigure(wwin, src_x + off_x, src_y + off_y, ww, wh - vert_border);
1520 wWindowSynthConfigureNotify(wwin);
1521 }
1522 wWindowChangeWorkspace(wwin, scr->current_workspace);
1523 wSetFocusTo(scr, wwin);
1524 }
1525
1526 if (wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 &&
1527 head != wGetHeadForWindow(wwin)) {
1528 wArrangeIcons(scr, True);
1529 }
1530
1531 #if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP)
1532 wWorkspaceResizeViewport(scr, scr->current_workspace);
1533 #endif
1534
1535 return 1;
1536 }
1537 }
1538 }
1539
1540 /*
1541 *----------------------------------------------------------------------
1542 * wMouseMoveWindow--
1543 * Move the named window and the other selected ones (if any),
1544 * interactively. Also shows the position of the window, if only one
1545 * window is being moved.
1546 * If the window is not on the selected window list, the selected
1547 * windows are deselected.
1548 * If shift is pressed during the operation, the position display
1549 * is changed to another type.
1550 *
1551 * Returns:
1552 * True if the window was moved, False otherwise.
1553 *
1554 * Side effects:
1555 * The window(s) position is changed, and the client(s) are
1556 * notified about that.
1557 * The position display configuration may be changed.
1558 *----------------------------------------------------------------------
1559 */
1560 int wMouseMoveWindow(WWindow * wwin, XEvent * ev)
1561 {
1562 WScreen *scr = wwin->screen_ptr;
1563 XEvent event;
1564 Window root = scr->root_win;
1565 KeyCode shiftl, shiftr;
1566 Bool done = False;
1567 int started = 0;
1568 int warped = 0;
1569 /* This needs not to change while moving, else bad things can happen */
1570 int opaqueMove = wPreferences.opaque_move;
1571 MoveData moveData;
1572 int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1)
1573 ? wGetHeadForWindow(wwin)
1574 : scr->xine_info.primary_head);
1575 #ifdef GHOST_WINDOW_MOVE
1576 RImage *rimg = InitGhostWindowMove(scr);
1577 #endif
1578
1579 if (!IS_MOVABLE(wwin))
1580 return False;
1581
1582 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1583 XSetWindowAttributes attr;
1584
1585 attr.save_under = True;
1586 XChangeWindowAttributes(dpy, wwin->frame->core->window, CWSaveUnder, &attr);
1587 }
1588
1589 initMoveData(wwin, &moveData);
1590
1591 moveData.mouseX = ev->xmotion.x_root;
1592 moveData.mouseY = ev->xmotion.y_root;
1593
1594 if (!wwin->flags.selected) {
1595 /* this window is not selected, unselect others and move only wwin */
1596 wUnselectWindows(scr);
1597 }
1598 #ifdef DEBUG
1599 puts("Moving window");
1600 #endif
1601 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1602 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1603 while (!done) {
1604 if (warped) {
1605 int junk;
1606 Window junkw;
1607
1608 /* XWarpPointer() doesn't seem to generate Motion events, so
1609 * we've got to simulate them */
1610 XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
1611 &event.xmotion.y_root, &junk, &junk, (unsigned *)&junk);
1612 } else {
1613 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
1614 | PointerMotionHintMask
1615 | ButtonReleaseMask | ButtonPressMask | ExposureMask, &event);
1616
1617 if (event.type == MotionNotify) {
1618 /* compress MotionNotify events */
1619 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
1620 if (!checkMouseSamplingRate(&event))
1621 continue;
1622 }
1623 }
1624 switch (event.type) {
1625 case KeyPress:
1626 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1627 && started && !scr->selected_windows) {
1628
1629 if (!opaqueMove) {
1630 drawFrames(wwin, scr->selected_windows,
1631 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1632 }
1633
1634 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1635 showPosition(wwin, moveData.realX, moveData.realY);
1636 XUngrabServer(dpy);
1637 }
1638 cyclePositionDisplay(wwin, moveData.realX, moveData.realY,
1639 moveData.winWidth, moveData.winHeight);
1640
1641 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1642 XGrabServer(dpy);
1643 showPosition(wwin, moveData.realX, moveData.realY);
1644 }
1645
1646 if (!opaqueMove) {
1647 drawFrames(wwin, scr->selected_windows,
1648 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1649 }
1650 /*} else {
1651 WMHandleEvent(&event); this causes problems needs fixing */
1652 }
1653 break;
1654
1655 case MotionNotify:
1656 if (started) {
1657 updateWindowPosition(wwin, &moveData,
1658 scr->selected_windows == NULL
1659 && wPreferences.edge_resistance > 0,
1660 opaqueMove, event.xmotion.x_root, event.xmotion.y_root);
1661
1662 if (!warped && !wPreferences.no_autowrap) {
1663 int oldWorkspace = scr->current_workspace;
1664
1665 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1666 showPosition(wwin, moveData.realX, moveData.realY);
1667 XUngrabServer(dpy);
1668 }
1669 if (!opaqueMove) {
1670 drawFrames(wwin, scr->selected_windows,
1671 moveData.realX - wwin->frame_x,
1672 moveData.realY - wwin->frame_y);
1673 }
1674 if (checkWorkspaceChange(wwin, &moveData, opaqueMove)) {
1675 if (scr->current_workspace != oldWorkspace
1676 && wPreferences.edge_resistance > 0
1677 && scr->selected_windows == NULL)
1678 updateMoveData(wwin, &moveData);
1679 warped = 1;
1680 }
1681 if (!opaqueMove) {
1682 drawFrames(wwin, scr->selected_windows,
1683 moveData.realX - wwin->frame_x,
1684 moveData.realY - wwin->frame_y);
1685 }
1686 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1687 XSync(dpy, False);
1688 showPosition(wwin, moveData.realX, moveData.realY);
1689 XGrabServer(dpy);
1690 }
1691 } else {
1692 warped = 0;
1693 }
1694 } else if (abs(ev->xmotion.x_root - event.xmotion.x_root) >= MOVE_THRESHOLD
1695 || abs(ev->xmotion.y_root - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1696
1697 XChangeActivePointerGrab(dpy, ButtonMotionMask
1698 | ButtonReleaseMask | ButtonPressMask,
1699 wCursor[WCUR_MOVE], CurrentTime);
1700 started = 1;
1701 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1702
1703 if (!scr->selected_windows)
1704 mapPositionDisplay(wwin, moveData.realX, moveData.realY,
1705 moveData.winWidth, moveData.winHeight);
1706
1707 if (started && !opaqueMove)
1708 drawFrames(wwin, scr->selected_windows, 0, 0);
1709
1710 if (!opaqueMove || (wPreferences.move_display == WDIS_NEW
1711 && !scr->selected_windows)) {
1712 XGrabServer(dpy);
1713 if (wPreferences.move_display == WDIS_NEW)
1714 showPosition(wwin, moveData.realX, moveData.realY);
1715 }
1716 }
1717 break;
1718
1719 case ButtonPress:
1720 break;
1721
1722 case ButtonRelease:
1723 if (event.xbutton.button != ev->xbutton.button)
1724 break;
1725
1726 if (started) {
1727 XEvent e;
1728 if (!opaqueMove) {
1729 drawFrames(wwin, scr->selected_windows,
1730 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1731 XSync(dpy, 0);
1732 doWindowMove(wwin, scr->selected_windows,
1733 moveData.realX - wwin->frame_x,
1734 moveData.realY - wwin->frame_y);
1735 }
1736 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
1737 wWindowSynthConfigureNotify(wwin);
1738 #endif
1739 XUngrabKeyboard(dpy, CurrentTime);
1740 XUngrabServer(dpy);
1741 if (!opaqueMove) {
1742 wWindowChangeWorkspace(wwin, scr->current_workspace);
1743 wSetFocusTo(scr, wwin);
1744 }
1745 if (wPreferences.move_display == WDIS_NEW)
1746 showPosition(wwin, moveData.realX, moveData.realY);
1747
1748 /* discard all enter/leave events that happened until
1749 * the time the button was released */
1750 while (XCheckTypedEvent(dpy, EnterNotify, &e)) {
1751 if (e.xcrossing.time > event.xbutton.time) {
1752 XPutBackEvent(dpy, &e);
1753 break;
1754 }
1755 }
1756 while (XCheckTypedEvent(dpy, LeaveNotify, &e)) {
1757 if (e.xcrossing.time > event.xbutton.time) {
1758 XPutBackEvent(dpy, &e);
1759 break;
1760 }
1761 }
1762
1763 if (!scr->selected_windows) {
1764 /* get rid of the geometry window */
1765 WMUnmapWidget(scr->gview);
1766 }
1767 }
1768 #ifdef DEBUG
1769 puts("End move window");
1770 #endif
1771 done = True;
1772 break;
1773
1774 default:
1775 if (started && !opaqueMove) {
1776 drawFrames(wwin, scr->selected_windows,
1777 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1778 XUngrabServer(dpy);
1779 WMHandleEvent(&event);
1780 XSync(dpy, False);
1781 XGrabServer(dpy);
1782 drawFrames(wwin, scr->selected_windows,
1783 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1784 } else {
1785 WMHandleEvent(&event);
1786 }
1787 break;
1788 }
1789 }
1790
1791 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1792 XSetWindowAttributes attr;
1793
1794 attr.save_under = False;
1795 XChangeWindowAttributes(dpy, wwin->frame->core->window, CWSaveUnder, &attr);
1796
1797 }
1798
1799 freeMoveData(&moveData);
1800
1801 if (started && wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 &&
1802 head != wGetHeadForWindow(wwin)) {
1803 wArrangeIcons(scr, True);
1804 }
1805 #if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP)
1806 if (started)
1807 wWorkspaceResizeViewport(scr, scr->current_workspace);
1808 #endif
1809
1810 return started;
1811 }
1812
1813 #define RESIZEBAR 1
1814 #define HCONSTRAIN 2
1815
1816 static int getResizeDirection(WWindow * wwin, int x, int y, int dx, int dy, int flags)
1817 {
1818 int w = wwin->frame->core->width - 1;
1819 int cw = wwin->frame->resizebar_corner_width;
1820 int dir;
1821
1822 /* if not resizing through the resizebar */
1823 if (!(flags & RESIZEBAR)) {
1824 int xdir = (abs(x) < (wwin->client.width / 2)) ? LEFT : RIGHT;
1825 int ydir = (abs(y) < (wwin->client.height / 2)) ? UP : DOWN;
1826 if (abs(dx) < 2 || abs(dy) < 2) {
1827 if (abs(dy) > abs(dx))
1828 xdir = 0;
1829 else
1830 ydir = 0;
1831 }
1832 return (xdir | ydir);
1833 }
1834
1835 /* window is too narrow. allow diagonal resize */
1836 if (cw * 2 >= w) {
1837 int ydir;
1838
1839 if (flags & HCONSTRAIN)
1840 ydir = 0;
1841 else
1842 ydir = DOWN;
1843 if (x < cw)
1844 return (LEFT | ydir);
1845 else
1846 return (RIGHT | ydir);
1847 }
1848 /* vertical resize */
1849 if ((x > cw) && (x < w - cw))
1850 return DOWN;
1851
1852 if (x < cw)
1853 dir = LEFT;
1854 else
1855 dir = RIGHT;
1856
1857 if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
1858 dir |= DOWN;
1859
1860 return dir;
1861 }
1862
1863 void wMouseResizeWindow(WWindow * wwin, XEvent * ev)
1864 {
1865 XEvent event;
1866 WScreen *scr = wwin->screen_ptr;
1867 Window root = scr->root_win;
1868 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1869 int fw = wwin->frame->core->width;
1870 int fh = wwin->frame->core->height;
1871 int fx = wwin->frame_x;
1872 int fy = wwin->frame_y;
1873 int is_resizebar = (wwin->frame->resizebar && ev->xany.window == wwin->frame->resizebar->window);
1874 int orig_x, orig_y;
1875 int started;
1876 int dw, dh;
1877 int rw = fw, rh = fh;
1878 int rx1, ry1, rx2, ry2;
1879 int res = 0;
1880 KeyCode shiftl, shiftr;
1881 int h = 0;
1882 int orig_fx = fx;
1883 int orig_fy = fy;
1884 int orig_fw = fw;
1885 int orig_fh = fh;
1886 int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1)
1887 ? wGetHeadForWindow(wwin)
1888 : scr->xine_info.primary_head);
1889
1890 if (!IS_RESIZABLE(wwin))
1891 return;
1892
1893 if (wwin->flags.shaded) {
1894 wwarning("internal error: tryein");
1895 return;
1896 }
1897 orig_x = ev->xbutton.x_root;
1898 orig_y = ev->xbutton.y_root;
1899
1900 started = 0;
1901 #ifdef DEBUG
1902 puts("Resizing window");
1903 #endif
1904
1905 wUnselectWindows(scr);
1906 rx1 = fx;
1907 rx2 = fx + fw - 1;
1908 ry1 = fy;
1909 ry2 = fy + fh - 1;
1910 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1911 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1912 if (HAS_TITLEBAR(wwin))
1913 h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance +
1914 TITLEBAR_EXTEND_SPACE) * 2;
1915 else
1916 h = 0;
1917 while (1) {
1918 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
1919 | ButtonReleaseMask | PointerMotionHintMask | ButtonPressMask | ExposureMask, &event);
1920 if (!checkMouseSamplingRate(&event))
1921 continue;
1922
1923 switch (event.type) {
1924 case KeyPress:
1925 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1926 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1927 && started) {
1928 drawTransparentFrame(wwin, fx, fy, fw, fh);
1929 cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
1930 drawTransparentFrame(wwin, fx, fy, fw, fh);
1931 }
1932 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1933 break;
1934
1935 case MotionNotify:
1936 if (started) {
1937 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
1938
1939 dw = 0;
1940 dh = 0;
1941
1942 orig_fx = fx;
1943 orig_fy = fy;
1944 orig_fw = fw;
1945 orig_fh = fh;
1946
1947 if (res & LEFT)
1948 dw = orig_x - event.xmotion.x_root;
1949 else if (res & RIGHT)
1950 dw = event.xmotion.x_root - orig_x;
1951 if (res & UP)
1952 dh = orig_y - event.xmotion.y_root;
1953 else if (res & DOWN)
1954 dh = event.xmotion.y_root - orig_y;
1955
1956 orig_x = event.xmotion.x_root;
1957 orig_y = event.xmotion.y_root;
1958
1959 rw += dw;
1960 rh += dh;
1961 fw = rw;
1962 fh = rh - vert_border;
1963 wWindowConstrainSize(wwin, (unsigned int *)&fw, (unsigned int *)&fh);
1964 fh += vert_border;
1965 if (res & LEFT)
1966 fx = rx2 - fw + 1;
1967 else if (res & RIGHT)
1968 fx = rx1;
1969 if (res & UP)
1970 fy = ry2 - fh + 1;
1971 else if (res & DOWN)
1972 fy = ry1;
1973 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
1974 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1975 int tx, ty;
1976 Window junkw;
1977 int flags;
1978
1979 XTranslateCoordinates(dpy, root, wwin->frame->core->window,
1980 orig_x, orig_y, &tx, &ty, &junkw);
1981
1982 /* check if resizing through resizebar */
1983 if (is_resizebar)
1984 flags = RESIZEBAR;
1985 else
1986 flags = 0;
1987
1988 if (is_resizebar && ((ev->xbutton.state & ShiftMask)
1989 || abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
1990 flags |= HCONSTRAIN;
1991
1992 res = getResizeDirection(wwin, tx, ty,
1993 orig_x - event.xmotion.x_root,
1994 orig_y - event.xmotion.y_root, flags);
1995
1996 if (res == (UP | LEFT))
1997 XChangeActivePointerGrab(dpy, ButtonMotionMask
1998 | ButtonReleaseMask | ButtonPressMask,
1999 wCursor[WCUR_TOPLEFTRESIZE], CurrentTime);
2000 else if (res == (UP | RIGHT))
2001 XChangeActivePointerGrab(dpy, ButtonMotionMask
2002 | ButtonReleaseMask | ButtonPressMask,
2003 wCursor[WCUR_TOPRIGHTRESIZE], CurrentTime);
2004 else if (res == (DOWN | LEFT))
2005 XChangeActivePointerGrab(dpy, ButtonMotionMask
2006 | ButtonReleaseMask | ButtonPressMask,
2007 wCursor[WCUR_BOTTOMLEFTRESIZE], CurrentTime);
2008 else if (res == (DOWN | RIGHT))
2009 XChangeActivePointerGrab(dpy, ButtonMotionMask
2010 | ButtonReleaseMask | ButtonPressMask,
2011 wCursor[WCUR_BOTTOMRIGHTRESIZE], CurrentTime);
2012 else if (res == DOWN || res == UP)
2013 XChangeActivePointerGrab(dpy, ButtonMotionMask
2014 | ButtonReleaseMask | ButtonPressMask,
2015 wCursor[WCUR_VERTICALRESIZE], CurrentTime);
2016 else if (res & (DOWN | UP))
2017 XChangeActivePointerGrab(dpy, ButtonMotionMask
2018 | ButtonReleaseMask | ButtonPressMask,
2019 wCursor[WCUR_VERTICALRESIZE], CurrentTime);
2020 else if (res & (LEFT | RIGHT))
2021 XChangeActivePointerGrab(dpy, ButtonMotionMask
2022 | ButtonReleaseMask | ButtonPressMask,
2023 wCursor[WCUR_HORIZONRESIZE], CurrentTime);
2024
2025 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
2026
2027 XGrabServer(dpy);
2028
2029 /* Draw the resize frame for the first time. */
2030 mapGeometryDisplay(wwin, fx, fy, fw, fh);
2031
2032 drawTransparentFrame(wwin, fx, fy, fw, fh);
2033
2034 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2035
2036 started = 1;
2037 }
2038 if (started) {
2039 if (wPreferences.size_display == WDIS_FRAME_CENTER) {
2040 drawTransparentFrame(wwin, orig_fx, orig_fy, orig_fw, orig_fh);
2041 moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
2042 drawTransparentFrame(wwin, fx, fy, fw, fh);
2043 } else {
2044 drawTransparentFrame(wwin, orig_fx, orig_fy, orig_fw, orig_fh);
2045 drawTransparentFrame(wwin, fx, fy, fw, fh);
2046 }
2047 if (fh != orig_fh || fw != orig_fw) {
2048 if (wPreferences.size_display == WDIS_NEW) {
2049 showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw,
2050 orig_fy + orig_fh, res);
2051 }
2052 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2053 }
2054 }
2055 break;
2056
2057 case ButtonPress:
2058 break;
2059
2060 case ButtonRelease:
2061 if (event.xbutton.button != ev->xbutton.button)
2062 break;
2063
2064 if (started) {
2065 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2066
2067 drawTransparentFrame(wwin, fx, fy, fw, fh);
2068
2069 XUngrabKeyboard(dpy, CurrentTime);
2070 WMUnmapWidget(scr->gview);
2071 XUngrabServer(dpy);
2072
2073 if (wwin->client.width != fw)
2074 wwin->flags.user_changed_width = 1;
2075
2076 if (wwin->client.height != fh - vert_border)
2077 wwin->flags.user_changed_height = 1;
2078
2079 wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
2080 }
2081 #ifdef DEBUG
2082 puts("End resize window");
2083 #endif
2084 return;
2085
2086 default:
2087 WMHandleEvent(&event);
2088 }
2089 }
2090
2091 if (wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 && head != wGetHeadForWindow(wwin)) {
2092 wArrangeIcons(scr, True);
2093 }
2094 #if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP)
2095 wWorkspaceResizeViewport(scr, scr->current_workspace);
2096 #endif
2097 }
2098
2099 #undef LEFT
2100 #undef RIGHT
2101 #undef HORIZONTAL
2102 #undef UP
2103 #undef DOWN
2104 #undef VERTICAL
2105 #undef HCONSTRAIN
2106 #undef RESIZEBAR
2107
2108 void wUnselectWindows(WScreen * scr)
2109 {
2110 WWindow *wwin;
2111
2112 if (!scr->selected_windows)
2113 return;
2114
2115 while (WMGetArrayItemCount(scr->selected_windows)) {
2116 wwin = WMGetFromArray(scr->selected_windows, 0);
2117 if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
2118 wIconSelect(wwin->icon);
2119
2120 wSelectWindow(wwin, False);
2121 }
2122 WMFreeArray(scr->selected_windows);
2123 scr->selected_windows = NULL;
2124 }
2125
2126 #ifndef LITE
2127 static void selectWindowsInside(WScreen * scr, int x1, int y1, int x2, int y2)
2128 {
2129 WWindow *tmpw;
2130
2131 /* select the windows and put them in the selected window list */
2132 tmpw = scr->focused_window;
2133 while (tmpw != NULL) {
2134 if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
2135 if ((tmpw->frame->workspace == scr->current_workspace || IS_OMNIPRESENT(tmpw))
2136 && (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1)
2137 && (tmpw->frame->core->width + tmpw->frame_x <= x2)
2138 && (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
2139 wSelectWindow(tmpw, True);
2140 }
2141 }
2142 tmpw = tmpw->prev;
2143 }
2144 }
2145
2146 void wSelectWindows(WScreen * scr, XEvent * ev)
2147 {
2148 XEvent event;
2149 Window root = scr->root_win;
2150 GC gc = scr->frame_gc;
2151 int xp = ev->xbutton.x_root;
2152 int yp = ev->xbutton.y_root;
2153 int w = 0, h = 0;
2154 int x = xp, y = yp;
2155
2156 #ifdef DEBUG
2157 puts("Selecting windows");
2158 #endif
2159 if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
2160 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
2161 GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
2162 return;
2163 }
2164 XGrabServer(dpy);
2165
2166 wUnselectWindows(scr);
2167
2168 XDrawRectangle(dpy, root, gc, xp, yp, w, h);
2169 while (1) {
2170 WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask | ButtonPressMask, &event);
2171
2172 switch (event.type) {
2173 case MotionNotify:
2174 XDrawRectangle(dpy, root, gc, x, y, w, h);
2175 x = event.xmotion.x_root;
2176 if (x < xp) {
2177 w = xp - x;
2178 } else {
2179 w = x - xp;
2180 x = xp;
2181 }
2182 y = event.xmotion.y_root;
2183 if (y < yp) {
2184 h = yp - y;
2185 } else {
2186 h = y - yp;
2187 y = yp;
2188 }
2189 XDrawRectangle(dpy, root, gc, x, y, w, h);
2190 break;
2191
2192 case ButtonPress:
2193 break;
2194
2195 case ButtonRelease:
2196 if (event.xbutton.button != ev->xbutton.button)
2197 break;
2198
2199 XDrawRectangle(dpy, root, gc, x, y, w, h);
2200 XUngrabServer(dpy);
2201 XUngrabPointer(dpy, CurrentTime);
2202 selectWindowsInside(scr, x, y, x + w, y + h);
2203
2204 #ifdef DEBUG
2205 puts("End window selection");
2206 #endif
2207 return;
2208
2209 default:
2210 WMHandleEvent(&event);
2211 break;
2212 }
2213 }
2214 }
2215 #endif /* !LITE */
2216
2217 void InteractivePlaceWindow(WWindow * wwin, int *x_ret, int *y_ret, unsigned width, unsigned height)
2218 {
2219 WScreen *scr = wwin->screen_ptr;
2220 Window root = scr->root_win;
2221 int x, y, h = 0;
2222 XEvent event;
2223 KeyCode shiftl, shiftr;
2224 Window junkw;
2225 int junk;
2226
2227 if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
2228 GrabModeAsync, GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
2229 *x_ret = 0;
2230 *y_ret = 0;
2231 return;
2232 }
2233 if (HAS_TITLEBAR(wwin)) {
2234 h = WMFontHeight(scr->title_font) + (wPreferences.window_title_clearance +
2235 TITLEBAR_EXTEND_SPACE) * 2;
2236 height += h;
2237 }
2238 if (HAS_RESIZEBAR(wwin)) {
2239 height += RESIZEBAR_HEIGHT;
2240 }
2241 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
2242 XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk, (unsigned *)&junk);
2243 mapPositionDisplay(wwin, x - width / 2, y - h / 2, width, height);
2244
2245 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2246
2247 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
2248 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
2249 while (1) {
2250 WMMaskEvent(dpy, PointerMotionMask | ButtonPressMask | ExposureMask | KeyPressMask, &event);
2251
2252 if (!checkMouseSamplingRate(&event))
2253 continue;
2254
2255 switch (event.type) {
2256 case KeyPress:
2257 if ((event.xkey.keycode == shiftl)
2258 || (event.xkey.keycode == shiftr)) {
2259 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2260 cyclePositionDisplay(wwin, x - width / 2, y - h / 2, width, height);
2261 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2262 }
2263 break;
2264
2265 case MotionNotify:
2266 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2267
2268 x = event.xmotion.x_root;
2269 y = event.xmotion.y_root;
2270
2271 if (wPreferences.move_display == WDIS_FRAME_CENTER)
2272 moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
2273
2274 showPosition(wwin, x - width / 2, y - h / 2);
2275
2276 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2277
2278 break;
2279
2280 case ButtonPress:
2281 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2282 XSync(dpy, 0);
2283 *x_ret = x - width / 2;
2284 *y_ret = y - h / 2;
2285 XUngrabPointer(dpy, CurrentTime);
2286 XUngrabKeyboard(dpy, CurrentTime);
2287 /* get rid of the geometry window */
2288 WMUnmapWidget(scr->gview);
2289 return;
2290
2291 default:
2292 WMHandleEvent(&event);
2293 break;
2294 }
2295 }
2296 }