Mac OS X-style window cycling.
[wmaker-crm.git] / src / moveres.c
blobf2b6966aa65148e49b2a7f2126794f6ebc1eb56e
1 /*
2 * Window Maker window manager
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
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.
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.
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.
22 #include "wconfig.h"
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>
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"
43 #include "geomview.h"
44 #include "screen.h"
45 #include "xinerama.h"
47 #include <WINGs/WINGsP.h>
49 /* How many different types of geometry/position
50 display thingies are there? */
51 #define NUM_DISPLAYS 5
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)
60 /* True if window currently has a border. This also includes borderless
61 * windows which are currently selected
63 #define HAS_BORDER_WITH_SELECT(w) ((w)->flags.selected || HAS_BORDER(w))
65 /****** Global Variables ******/
66 extern Time LastTimestamp;
68 extern Cursor wCursor[WCUR_LAST];
70 extern WPreferences wPreferences;
72 extern Atom _XA_WM_PROTOCOLS;
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 *----------------------------------------------------------------------
82 static Bool checkMouseSamplingRate(XEvent * ev)
84 static Time previousMotion = 0;
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;
93 return True;
97 *----------------------------------------------------------------------
98 * moveGeometryDisplayCentered
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 *----------------------------------------------------------------------
105 static void moveGeometryDisplayCentered(WScreen * scr, int x, int y)
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;
111 x -= w / 2;
112 y -= h / 2;
114 /* dead area check */
115 if (scr->xine_info.count) {
116 WMRect rect;
117 int head, flags;
119 rect.pos.x = x;
120 rect.pos.y = y;
121 rect.size.width = w;
122 rect.size.height = h;
124 head = wGetRectPlacementInfo(scr, rect, &flags);
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;
135 if (x < x1 + 1)
136 x = x1 + 1;
137 else if (x > (x2 - w))
138 x = x2 - w;
140 if (y < y1 + 1)
141 y = y1 + 1;
142 else if (y > (y2 - h))
143 y = y2 - h;
145 WMMoveWidget(scr->gview, x, y);
148 static void showPosition(WWindow * wwin, int x, int y)
150 WScreen *scr = wwin->screen_ptr;
152 if (wPreferences.move_display == WDIS_NEW) {
153 #if 0
154 int width = wwin->frame->core->width;
155 int height = wwin->frame->core->height;
157 GC lgc = scr->line_gc;
158 XSetForeground(dpy, lgc, scr->line_pixel);
159 sprintf(num, "%i", x);
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
177 static void cyclePositionDisplay(WWindow * wwin, int x, int y, int w, int h)
179 WScreen *scr = wwin->screen_ptr;
180 WMRect rect;
182 wPreferences.move_display++;
183 wPreferences.move_display %= NUM_DISPLAYS;
185 if (wPreferences.move_display == WDIS_NEW) {
186 wPreferences.move_display++;
187 wPreferences.move_display %= NUM_DISPLAYS;
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);
203 WMMapWidget(scr->gview);
207 static void mapPositionDisplay(WWindow * wwin, int x, int y, int w, int h)
209 WScreen *scr = wwin->screen_ptr;
210 WMRect rect;
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);
224 WMMapWidget(scr->gview);
225 WSetGeometryViewShownPosition(scr->gview, x, y);
228 static void showGeometry(WWindow * wwin, int x1, int y1, int x2, int y2, int direction)
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;
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--;
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;
250 ty = y1 + wwin->frame->top_width;
251 by = y2 - wwin->frame->bottom_width;
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;
257 XSetForeground(dpy, gc, scr->line_pixel);
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;
267 my = (ty + by) / 2;
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;
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;
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;
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;
292 XDrawSegments(dpy, root, gc, segment, 4);
294 /* bottom arrow & end bar */
295 segment[0].y1 = by;
296 segment[0].y2 = by;
298 /* arrowhead */
299 segment[1].y1 = by - 1;
300 segment[1].y2 = by - 7;
302 segment[2].y1 = by - 1;
303 segment[2].y2 = by - 7;
305 /* line */
306 segment[3].y1 = my + fh / 2 + 2;
307 segment[3].y2 = by - 1;
309 XDrawSegments(dpy, root, gc, segment, 4);
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));
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));
320 /* horizontal geometry */
321 if (y1 < 15) {
322 y = y2;
323 s = -15;
324 } else {
325 y = y1;
326 s = 15;
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));
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);
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);
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);
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);
356 XDrawSegments(dpy, root, gc, segment, 4);
358 /* right arrow & end bar */
359 segment[0].x1 = x2 + 1;
360 segment[0].x2 = x2 + 1;
362 /* arrowhead */
363 segment[1].x1 = x2 - 6;
364 segment[1].x2 = x2;
366 segment[2].x1 = x2;
367 segment[2].x2 = x2 - 6;
369 /* line */
370 segment[3].x1 = mx + fw / 2 + 2;
371 segment[3].x2 = x2;
373 XDrawSegments(dpy, root, gc, segment, 4);
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);
386 static void cycleGeometryDisplay(WWindow * wwin, int x, int y, int w, int h, int dir)
388 WScreen *scr = wwin->screen_ptr;
389 WMRect rect;
391 wPreferences.size_display++;
392 wPreferences.size_display %= NUM_DISPLAYS;
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);
407 WMMapWidget(scr->gview);
408 showGeometry(wwin, x, y, x + w, y + h, dir);
412 static void mapGeometryDisplay(WWindow * wwin, int x, int y, int w, int h)
414 WScreen *scr = wwin->screen_ptr;
415 WMRect rect;
417 if (wPreferences.size_display == WDIS_NEW || wPreferences.size_display == WDIS_NONE)
418 return;
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);
430 WMMapWidget(scr->gview);
431 showGeometry(wwin, x, y, x + w, y + h, 0);
434 static void doWindowMove(WWindow * wwin, WMArray * array, int dx, int dy)
436 WWindow *tmpw;
437 WScreen *scr = wwin->screen_ptr;
438 int x, y;
440 if (!array || !WMGetArrayItemCount(array)) {
441 wWindowMove(wwin, wwin->frame_x + dx, wwin->frame_y + dy);
442 } else {
443 WMArrayIterator iter;
445 WM_ITERATE_ARRAY(array, tmpw, iter) {
446 x = tmpw->frame_x + dx;
447 y = tmpw->frame_y + dy;
449 #if 1 /* XXX: with xinerama patch was #if 0, check this */
450 /* don't let windows become unreachable */
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;
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
466 wWindowMove(tmpw, x, y);
471 static void drawTransparentFrame(WWindow * wwin, int x, int y, int width, int height)
473 Window root = wwin->screen_ptr->root_win;
474 GC gc = wwin->screen_ptr->frame_gc;
475 int h = 0;
476 int bottom = 0;
478 if (HAS_BORDER_WITH_SELECT(wwin)) {
479 x += FRAME_BORDER_WIDTH;
480 y += FRAME_BORDER_WIDTH;
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;
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;
492 XDrawRectangle(dpy, root, gc, x - 1, y - 1, width + 1, height + 1);
494 if (h > 0) {
495 XDrawLine(dpy, root, gc, x, y + h - 1, x + width, y + h - 1);
497 if (bottom > 0) {
498 XDrawLine(dpy, root, gc, x, y + height - bottom, x + width, y + height - bottom);
502 static void drawFrames(WWindow * wwin, WMArray * array, int dx, int dy)
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;
509 if (!array) {
511 x = wwin->frame_x + dx;
512 y = wwin->frame_y + dy;
514 drawTransparentFrame(wwin, x, y, wwin->frame->core->width, wwin->frame->core->height);
516 } else {
517 WMArrayIterator iter;
519 WM_ITERATE_ARRAY(array, tmpw, iter) {
520 x = tmpw->frame_x + dx;
521 y = tmpw->frame_y + dy;
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;
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;
535 #else
536 wScreenBringInside(wwin->screen_ptr, &x, &y,
537 (int)tmpw->frame->core->width, (int)tmpw->frame->core->height);
538 #endif
540 drawTransparentFrame(tmpw, x, y, tmpw->frame->core->width, tmpw->frame->core->height);
545 static void flushMotion()
547 XEvent ev;
549 XSync(dpy, False);
550 while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
553 static void crossWorkspace(WScreen * scr, WWindow * wwin, int opaque_move, int new_workspace, int rewind)
555 /* do not let window be unmapped */
556 if (opaque_move) {
557 wwin->flags.changing_workspace = 1;
558 wWindowChangeWorkspace(wwin, new_workspace);
560 /* go to new workspace */
561 wWorkspaceChange(scr, new_workspace);
563 wwin->flags.changing_workspace = 0;
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);
570 flushMotion();
572 if (!opaque_move) {
573 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
574 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
575 GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
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;
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;
594 int rubCount; /* for workspace switching */
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;
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))
610 static int compareWTop(const void *a, const void *b)
612 WWindow *wwin1 = *(WWindow **) a;
613 WWindow *wwin2 = *(WWindow **) b;
615 if (WTOP(wwin1) > WTOP(wwin2))
616 return -1;
617 else if (WTOP(wwin1) < WTOP(wwin2))
618 return 1;
619 else
620 return 0;
623 static int compareWLeft(const void *a, const void *b)
625 WWindow *wwin1 = *(WWindow **) a;
626 WWindow *wwin2 = *(WWindow **) b;
628 if (WLEFT(wwin1) > WLEFT(wwin2))
629 return -1;
630 else if (WLEFT(wwin1) < WLEFT(wwin2))
631 return 1;
632 else
633 return 0;
636 static int compareWRight(const void *a, const void *b)
638 WWindow *wwin1 = *(WWindow **) a;
639 WWindow *wwin2 = *(WWindow **) b;
641 if (WRIGHT(wwin1) < WRIGHT(wwin2))
642 return -1;
643 else if (WRIGHT(wwin1) > WRIGHT(wwin2))
644 return 1;
645 else
646 return 0;
649 static int compareWBottom(const void *a, const void *b)
651 WWindow *wwin1 = *(WWindow **) a;
652 WWindow *wwin2 = *(WWindow **) b;
654 if (WBOTTOM(wwin1) < WBOTTOM(wwin2))
655 return -1;
656 else if (WBOTTOM(wwin1) > WBOTTOM(wwin2))
657 return 1;
658 else
659 return 0;
662 static void updateResistance(WWindow * wwin, MoveData * data, int newX, int newY)
664 int i;
665 int newX2 = newX + data->winWidth;
666 int newY2 = newY + data->winHeight;
667 Bool ok = False;
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;
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;
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;
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;
702 if (!ok)
703 return;
705 /* TODO: optimize this */
706 if (data->realY < WBOTTOM(data->bottomList[0])) {
707 data->bottomIndex = 0;
709 if (data->realX < WRIGHT(data->rightList[0])) {
710 data->rightIndex = 0;
712 if ((data->realX + data->winWidth) > WLEFT(data->leftList[0])) {
713 data->leftIndex = 0;
715 if ((data->realY + data->winHeight) > WTOP(data->topList[0])) {
716 data->topIndex = 0;
718 for (i = 0; i < data->count; i++) {
719 if (data->realY > WBOTTOM(data->bottomList[i])) {
720 data->bottomIndex = i + 1;
722 if (data->realX > WRIGHT(data->rightList[i])) {
723 data->rightIndex = i + 1;
725 if ((data->realX + data->winWidth) < WLEFT(data->leftList[i])) {
726 data->leftIndex = i + 1;
728 if ((data->realY + data->winHeight) < WTOP(data->topList[i])) {
729 data->topIndex = i + 1;
734 static void freeMoveData(MoveData * data)
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);
746 static void updateMoveData(WWindow * wwin, MoveData * data)
748 WScreen *scr = wwin->screen_ptr;
749 WWindow *tmp;
750 int i;
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++;
764 tmp = tmp->prev;
767 if (data->count == 0) {
768 data->topIndex = 0;
769 data->leftIndex = 0;
770 data->rightIndex = 0;
771 data->bottomIndex = 0;
772 return;
775 /* order from closest to the border of the screen to farthest */
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);
782 /* figure the position of the window relative to the others */
784 data->topIndex = -1;
785 data->leftIndex = -1;
786 data->rightIndex = -1;
787 data->bottomIndex = -1;
789 if (WTOP(wwin) < WBOTTOM(data->bottomList[0])) {
790 data->bottomIndex = 0;
792 if (WLEFT(wwin) < WRIGHT(data->rightList[0])) {
793 data->rightIndex = 0;
795 if (WRIGHT(wwin) > WLEFT(data->leftList[0])) {
796 data->leftIndex = 0;
798 if (WBOTTOM(wwin) > WTOP(data->topList[0])) {
799 data->topIndex = 0;
801 for (i = 0; i < data->count; i++) {
802 if (WTOP(wwin) >= WBOTTOM(data->bottomList[i])) {
803 data->bottomIndex = i + 1;
805 if (WLEFT(wwin) >= WRIGHT(data->rightList[i])) {
806 data->rightIndex = i + 1;
808 if (WRIGHT(wwin) <= WLEFT(data->leftList[i])) {
809 data->leftIndex = i + 1;
811 if (WBOTTOM(wwin) <= WTOP(data->topList[i])) {
812 data->topIndex = i + 1;
817 static void initMoveData(WWindow * wwin, MoveData * data)
819 int i;
820 WWindow *tmp;
822 memset(data, 0, sizeof(MoveData));
824 for (i = 0, tmp = wwin->screen_ptr->focused_window; tmp != NULL; tmp = tmp->prev, i++) ;
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);
832 updateMoveData(wwin, data);
835 data->realX = wwin->frame_x;
836 data->realY = wwin->frame_y;
837 data->calcX = wwin->frame_x;
838 data->calcY = wwin->frame_y;
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);
844 static Bool checkWorkspaceChange(WWindow * wwin, MoveData * data, Bool opaqueMove)
846 WScreen *scr = wwin->screen_ptr;
847 Bool changed = False;
849 if (data->mouseX <= 1) {
850 if (scr->current_workspace > 0) {
852 crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace - 1, True);
853 changed = True;
854 data->rubCount = 0;
856 } else if (scr->current_workspace == 0 && wPreferences.ws_cycle) {
858 crossWorkspace(scr, wwin, opaqueMove, scr->workspace_count - 1, True);
859 changed = True;
860 data->rubCount = 0;
862 } else if (data->mouseX >= scr->scr_width - 2) {
864 if (scr->current_workspace == scr->workspace_count - 1) {
866 if (wPreferences.ws_cycle || scr->workspace_count == MAX_WORKSPACES) {
868 crossWorkspace(scr, wwin, opaqueMove, 0, False);
869 changed = True;
870 data->rubCount = 0;
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) {
876 /* detect user "rubbing" the window against the edge */
877 if (data->rubCount > 0 && data->omouseY - data->mouseY > MOVE_THRESHOLD) {
879 data->rubCount = -(data->rubCount + 1);
881 } else if (data->rubCount <= 0 && data->mouseY - data->omouseY > MOVE_THRESHOLD) {
883 data->rubCount = -data->rubCount + 1;
886 /* create a new workspace */
887 if (abs(data->rubCount) > 2) {
888 /* go to next workspace */
889 wWorkspaceNew(scr);
891 crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace + 1, False);
892 changed = True;
893 data->rubCount = 0;
895 } else if (scr->current_workspace < scr->workspace_count) {
897 /* go to next workspace */
898 crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace + 1, False);
899 changed = True;
900 data->rubCount = 0;
902 } else {
903 data->rubCount = 0;
906 return changed;
909 static void
910 updateWindowPosition(WWindow * wwin, MoveData * data, Bool doResistance,
911 Bool opaqueMove, int newMouseX, int newMouseY)
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;
921 hresist = False;
922 vresist = False;
924 updateIndex = False;
926 /* check the direction of the movement */
927 dx = newMouseX - data->mouseX;
928 dy = newMouseY - data->mouseY;
930 data->omouseX = data->mouseX;
931 data->omouseY = data->mouseY;
932 data->mouseX = newMouseX;
933 data->mouseY = newMouseY;
935 winL = data->calcX + dx;
936 winR = data->calcX + data->winWidth + dx;
937 winT = data->calcY + dy;
938 winB = data->calcY + data->winHeight + dy;
940 newX = data->realX;
941 newY = data->realY;
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;
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 */
958 /* Add inter head resistance 1/2 (if needed) */
959 head = wGetHeadForPointerLocation(scr);
960 rect = wGetRectForHead(scr, head);
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;
967 /* 1 */
968 if ((data->rightIndex >= 0) && (data->rightIndex <= data->count)) {
969 WWindow *looprw;
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);
979 break;
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;
996 if ((data->leftIndex >= 0) && (data->leftIndex <= data->count)) {
997 WWindow *looprw;
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);
1009 break;
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;
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);
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;
1038 } else {
1039 if (resist > 0 && attract && winL >= r_edge - resist && winL <= r_edge + resist) {
1040 newX = r_edge;
1041 hresist = True;
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;
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;
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;
1067 if ((data->bottomIndex >= 0) && (data->bottomIndex <= data->count)) {
1068 WWindow *looprw;
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);
1078 break;
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;
1095 if ((data->topIndex >= 0) && (data->topIndex <= data->count)) {
1096 WWindow *looprw;
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);
1108 break;
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;
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;
1132 } else {
1133 if (resist > 0 && attract && winT >= b_edge - resist && winT <= b_edge + resist) {
1134 newY = b_edge;
1135 vresist = True;
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;
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;
1154 /* END VeRT */
1158 /* update window position */
1159 data->calcX += dx;
1160 data->calcY += dy;
1162 if (((dx > 0 && data->calcX - data->realX > 0)
1163 || (dx < 0 && data->calcX - data->realX < 0)) && !hresist)
1164 newX = data->calcX;
1166 if (((dy > 0 && data->calcY - data->realY > 0)
1167 || (dy < 0 && data->calcY - data->realY < 0)) && !vresist)
1168 newY = data->calcY;
1170 if (data->realX != newX || data->realY != newY) {
1172 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1173 showPosition(wwin, data->realX, data->realY);
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);
1183 if (!scr->selected_windows && wPreferences.move_display == WDIS_FRAME_CENTER) {
1185 moveGeometryDisplayCentered(scr, newX + data->winWidth / 2, newY + data->winHeight / 2);
1188 if (!opaqueMove) {
1189 /* draw frames */
1190 drawFrames(wwin, scr->selected_windows, newX - wwin->frame_x, newY - wwin->frame_y);
1193 if (!scr->selected_windows) {
1194 showPosition(wwin, newX, newY);
1198 /* recalc relative window position */
1199 if (doResistance && (data->realX != newX || data->realY != newY)) {
1200 updateResistance(wwin, data, newX, newY);
1203 data->realX = newX;
1204 data->realY = newY;
1207 #define _KS KEY_CONTROL_WINDOW_WEIGHT
1209 #define MOVABLE_BIT 0x01
1210 #define RESIZABLE_BIT 0x02
1212 int wKeyboardMoveResizeWindow(WWindow * wwin)
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);
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;
1240 if (modes == RESIZABLE_BIT) {
1241 ctrlmode = 1;
1244 XSync(dpy, False);
1245 wusleep(10000);
1246 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1248 if (!wwin->flags.selected) {
1249 wUnselectWindows(scr);
1251 XGrabServer(dpy);
1252 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
1253 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
1254 GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime);
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);
1266 ww = w;
1267 wh = h;
1268 while (1) {
1270 looper.ox=off_x;
1271 looper.oy=off_y;
1273 do {
1274 WMMaskEvent(dpy, KeyPressMask | ButtonReleaseMask
1275 | ButtonPressMask | ExposureMask, &event);
1276 if (event.type == Expose) {
1277 WMHandleEvent(&event);
1279 } while (event.type == Expose);
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);
1291 if (ctrlmode)
1292 showGeometry(wwin, src_x + off_x, src_y + off_y, src_x + off_x + ww, src_y + off_y + wh,
1295 XUngrabServer(dpy);
1296 XSync(dpy, False);
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++;
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;
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 {
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;
1392 ww = w;
1393 wh = h;
1394 wh -= vert_border;
1395 wWindowConstrainSize(wwin, (unsigned int *)&ww, (unsigned int *)&wh);
1396 wh += vert_border;
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;
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;
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;
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);
1435 break;
1437 default:
1438 WMHandleEvent(&event);
1439 break;
1442 XGrabServer(dpy);
1443 /*xxx */
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);
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);
1466 if (ctrlmode) {
1467 showGeometry(wwin, src_x + off_x, src_y + off_y, src_x + off_x + ww, src_y + off_y + wh,
1469 } else if (!scr->selected_windows)
1470 showPosition(wwin, src_x + off_x, src_y + off_y);
1472 if (done) {
1473 scr->keymove_tick = 0;
1475 WMDeleteTimerWithClientData(&looper);
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);
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);
1493 XUngrabKeyboard(dpy, CurrentTime);
1494 XUngrabPointer(dpy, CurrentTime);
1495 XUngrabServer(dpy);
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;
1506 doWindowMove(wwin, scr->selected_windows, off_x, off_y);
1508 WM_ITERATE_ARRAY(scr->selected_windows, foo, iter) {
1509 wWindowSynthConfigureNotify(foo);
1512 } else {
1513 if (wwin->client.width != ww) {
1514 wwin->flags.user_changed_width = 1;
1515 wwin->flags.maximized &= ~(MAX_HORIZONTAL | MAX_MAXIMUS);
1518 if (wwin->client.height != wh - vert_border) {
1519 wwin->flags.user_changed_height = 1;
1520 wwin->flags.maximized &= ~(MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS);
1523 wWindowConfigure(wwin, src_x + off_x, src_y + off_y, ww, wh - vert_border);
1524 wWindowSynthConfigureNotify(wwin);
1526 wWindowChangeWorkspace(wwin, scr->current_workspace);
1527 wSetFocusTo(scr, wwin);
1530 if (wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 &&
1531 head != wGetHeadForWindow(wwin)) {
1532 wArrangeIcons(scr, True);
1535 #if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP)
1536 wWorkspaceResizeViewport(scr, scr->current_workspace);
1537 #endif
1539 return 1;
1545 *----------------------------------------------------------------------
1546 * wMouseMoveWindow--
1547 * Move the named window and the other selected ones (if any),
1548 * interactively. Also shows the position of the window, if only one
1549 * window is being moved.
1550 * If the window is not on the selected window list, the selected
1551 * windows are deselected.
1552 * If shift is pressed during the operation, the position display
1553 * is changed to another type.
1555 * Returns:
1556 * True if the window was moved, False otherwise.
1558 * Side effects:
1559 * The window(s) position is changed, and the client(s) are
1560 * notified about that.
1561 * The position display configuration may be changed.
1562 *----------------------------------------------------------------------
1564 int wMouseMoveWindow(WWindow * wwin, XEvent * ev)
1566 WScreen *scr = wwin->screen_ptr;
1567 XEvent event;
1568 Window root = scr->root_win;
1569 KeyCode shiftl, shiftr;
1570 Bool done = False;
1571 int started = 0;
1572 int warped = 0;
1573 /* This needs not to change while moving, else bad things can happen */
1574 int opaqueMove = wPreferences.opaque_move;
1575 MoveData moveData;
1576 int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1)
1577 ? wGetHeadForWindow(wwin)
1578 : scr->xine_info.primary_head);
1579 #ifdef GHOST_WINDOW_MOVE
1580 RImage *rimg = InitGhostWindowMove(scr);
1581 #endif
1583 if (!IS_MOVABLE(wwin))
1584 return False;
1586 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1587 XSetWindowAttributes attr;
1589 attr.save_under = True;
1590 XChangeWindowAttributes(dpy, wwin->frame->core->window, CWSaveUnder, &attr);
1593 initMoveData(wwin, &moveData);
1595 moveData.mouseX = ev->xmotion.x_root;
1596 moveData.mouseY = ev->xmotion.y_root;
1598 if (!wwin->flags.selected) {
1599 /* this window is not selected, unselect others and move only wwin */
1600 wUnselectWindows(scr);
1602 #ifdef DEBUG
1603 puts("Moving window");
1604 #endif
1605 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1606 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1607 while (!done) {
1608 if (warped) {
1609 int junk;
1610 Window junkw;
1612 /* XWarpPointer() doesn't seem to generate Motion events, so
1613 * we've got to simulate them */
1614 XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
1615 &event.xmotion.y_root, &junk, &junk, (unsigned *)&junk);
1616 } else {
1617 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
1618 | PointerMotionHintMask
1619 | ButtonReleaseMask | ButtonPressMask | ExposureMask, &event);
1621 if (event.type == MotionNotify) {
1622 /* compress MotionNotify events */
1623 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
1624 if (!checkMouseSamplingRate(&event))
1625 continue;
1628 switch (event.type) {
1629 case KeyPress:
1630 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1631 && started && !scr->selected_windows) {
1633 if (!opaqueMove) {
1634 drawFrames(wwin, scr->selected_windows,
1635 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1638 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1639 showPosition(wwin, moveData.realX, moveData.realY);
1640 XUngrabServer(dpy);
1642 cyclePositionDisplay(wwin, moveData.realX, moveData.realY,
1643 moveData.winWidth, moveData.winHeight);
1645 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1646 XGrabServer(dpy);
1647 showPosition(wwin, moveData.realX, moveData.realY);
1650 if (!opaqueMove) {
1651 drawFrames(wwin, scr->selected_windows,
1652 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1654 /*} else {
1655 WMHandleEvent(&event); this causes problems needs fixing */
1657 break;
1659 case MotionNotify:
1660 if (started) {
1661 updateWindowPosition(wwin, &moveData,
1662 scr->selected_windows == NULL
1663 && wPreferences.edge_resistance > 0,
1664 opaqueMove, event.xmotion.x_root, event.xmotion.y_root);
1666 if (!warped && !wPreferences.no_autowrap) {
1667 int oldWorkspace = scr->current_workspace;
1669 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1670 showPosition(wwin, moveData.realX, moveData.realY);
1671 XUngrabServer(dpy);
1673 if (!opaqueMove) {
1674 drawFrames(wwin, scr->selected_windows,
1675 moveData.realX - wwin->frame_x,
1676 moveData.realY - wwin->frame_y);
1678 if (checkWorkspaceChange(wwin, &moveData, opaqueMove)) {
1679 if (scr->current_workspace != oldWorkspace
1680 && wPreferences.edge_resistance > 0
1681 && scr->selected_windows == NULL)
1682 updateMoveData(wwin, &moveData);
1683 warped = 1;
1685 if (!opaqueMove) {
1686 drawFrames(wwin, scr->selected_windows,
1687 moveData.realX - wwin->frame_x,
1688 moveData.realY - wwin->frame_y);
1690 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1691 XSync(dpy, False);
1692 showPosition(wwin, moveData.realX, moveData.realY);
1693 XGrabServer(dpy);
1695 } else {
1696 warped = 0;
1698 } else if (abs(ev->xmotion.x_root - event.xmotion.x_root) >= MOVE_THRESHOLD
1699 || abs(ev->xmotion.y_root - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1701 XChangeActivePointerGrab(dpy, ButtonMotionMask
1702 | ButtonReleaseMask | ButtonPressMask,
1703 wCursor[WCUR_MOVE], CurrentTime);
1704 started = 1;
1705 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1707 if (!scr->selected_windows)
1708 mapPositionDisplay(wwin, moveData.realX, moveData.realY,
1709 moveData.winWidth, moveData.winHeight);
1711 if (started && !opaqueMove)
1712 drawFrames(wwin, scr->selected_windows, 0, 0);
1714 if (!opaqueMove || (wPreferences.move_display == WDIS_NEW
1715 && !scr->selected_windows)) {
1716 XGrabServer(dpy);
1717 if (wPreferences.move_display == WDIS_NEW)
1718 showPosition(wwin, moveData.realX, moveData.realY);
1721 break;
1723 case ButtonPress:
1724 break;
1726 case ButtonRelease:
1727 if (event.xbutton.button != ev->xbutton.button)
1728 break;
1730 if (started) {
1731 XEvent e;
1732 if (!opaqueMove) {
1733 drawFrames(wwin, scr->selected_windows,
1734 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1735 XSync(dpy, 0);
1736 doWindowMove(wwin, scr->selected_windows,
1737 moveData.realX - wwin->frame_x,
1738 moveData.realY - wwin->frame_y);
1740 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
1741 wWindowSynthConfigureNotify(wwin);
1742 #endif
1743 XUngrabKeyboard(dpy, CurrentTime);
1744 XUngrabServer(dpy);
1745 if (!opaqueMove) {
1746 wWindowChangeWorkspace(wwin, scr->current_workspace);
1747 wSetFocusTo(scr, wwin);
1749 if (wPreferences.move_display == WDIS_NEW)
1750 showPosition(wwin, moveData.realX, moveData.realY);
1752 /* discard all enter/leave events that happened until
1753 * the time the button was released */
1754 while (XCheckTypedEvent(dpy, EnterNotify, &e)) {
1755 if (e.xcrossing.time > event.xbutton.time) {
1756 XPutBackEvent(dpy, &e);
1757 break;
1760 while (XCheckTypedEvent(dpy, LeaveNotify, &e)) {
1761 if (e.xcrossing.time > event.xbutton.time) {
1762 XPutBackEvent(dpy, &e);
1763 break;
1767 if (!scr->selected_windows) {
1768 /* get rid of the geometry window */
1769 WMUnmapWidget(scr->gview);
1772 #ifdef DEBUG
1773 puts("End move window");
1774 #endif
1775 done = True;
1776 break;
1778 default:
1779 if (started && !opaqueMove) {
1780 drawFrames(wwin, scr->selected_windows,
1781 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1782 XUngrabServer(dpy);
1783 WMHandleEvent(&event);
1784 XSync(dpy, False);
1785 XGrabServer(dpy);
1786 drawFrames(wwin, scr->selected_windows,
1787 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1788 } else {
1789 WMHandleEvent(&event);
1791 break;
1795 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1796 XSetWindowAttributes attr;
1798 attr.save_under = False;
1799 XChangeWindowAttributes(dpy, wwin->frame->core->window, CWSaveUnder, &attr);
1803 freeMoveData(&moveData);
1805 if (started && wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 &&
1806 head != wGetHeadForWindow(wwin)) {
1807 wArrangeIcons(scr, True);
1809 #if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP)
1810 if (started)
1811 wWorkspaceResizeViewport(scr, scr->current_workspace);
1812 #endif
1814 return started;
1817 #define RESIZEBAR 1
1818 #define HCONSTRAIN 2
1820 static int getResizeDirection(WWindow * wwin, int x, int y, int dx, int dy, int flags)
1822 int w = wwin->frame->core->width - 1;
1823 int cw = wwin->frame->resizebar_corner_width;
1824 int dir;
1826 /* if not resizing through the resizebar */
1827 if (!(flags & RESIZEBAR)) {
1828 int xdir = (abs(x) < (wwin->client.width / 2)) ? LEFT : RIGHT;
1829 int ydir = (abs(y) < (wwin->client.height / 2)) ? UP : DOWN;
1830 if (abs(dx) < 2 || abs(dy) < 2) {
1831 if (abs(dy) > abs(dx))
1832 xdir = 0;
1833 else
1834 ydir = 0;
1836 return (xdir | ydir);
1839 /* window is too narrow. allow diagonal resize */
1840 if (cw * 2 >= w) {
1841 int ydir;
1843 if (flags & HCONSTRAIN)
1844 ydir = 0;
1845 else
1846 ydir = DOWN;
1847 if (x < cw)
1848 return (LEFT | ydir);
1849 else
1850 return (RIGHT | ydir);
1852 /* vertical resize */
1853 if ((x > cw) && (x < w - cw))
1854 return DOWN;
1856 if (x < cw)
1857 dir = LEFT;
1858 else
1859 dir = RIGHT;
1861 if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
1862 dir |= DOWN;
1864 return dir;
1867 void wMouseResizeWindow(WWindow * wwin, XEvent * ev)
1869 XEvent event;
1870 WScreen *scr = wwin->screen_ptr;
1871 Window root = scr->root_win;
1872 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1873 int fw = wwin->frame->core->width;
1874 int fh = wwin->frame->core->height;
1875 int fx = wwin->frame_x;
1876 int fy = wwin->frame_y;
1877 int is_resizebar = (wwin->frame->resizebar && ev->xany.window == wwin->frame->resizebar->window);
1878 int orig_x, orig_y;
1879 int started;
1880 int dw, dh;
1881 int rw = fw, rh = fh;
1882 int rx1, ry1, rx2, ry2;
1883 int res = 0;
1884 KeyCode shiftl, shiftr;
1885 int h = 0;
1886 int orig_fx = fx;
1887 int orig_fy = fy;
1888 int orig_fw = fw;
1889 int orig_fh = fh;
1890 int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1)
1891 ? wGetHeadForWindow(wwin)
1892 : scr->xine_info.primary_head);
1894 if (!IS_RESIZABLE(wwin))
1895 return;
1897 if (wwin->flags.shaded) {
1898 wwarning("internal error: tryein");
1899 return;
1901 orig_x = ev->xbutton.x_root;
1902 orig_y = ev->xbutton.y_root;
1904 started = 0;
1905 #ifdef DEBUG
1906 puts("Resizing window");
1907 #endif
1909 wUnselectWindows(scr);
1910 rx1 = fx;
1911 rx2 = fx + fw - 1;
1912 ry1 = fy;
1913 ry2 = fy + fh - 1;
1914 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1915 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1916 if (HAS_TITLEBAR(wwin))
1917 h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance +
1918 TITLEBAR_EXTEND_SPACE) * 2;
1919 else
1920 h = 0;
1921 while (1) {
1922 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
1923 | ButtonReleaseMask | PointerMotionHintMask | ButtonPressMask | ExposureMask, &event);
1924 if (!checkMouseSamplingRate(&event))
1925 continue;
1927 switch (event.type) {
1928 case KeyPress:
1929 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1930 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1931 && started) {
1932 drawTransparentFrame(wwin, fx, fy, fw, fh);
1933 cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
1934 drawTransparentFrame(wwin, fx, fy, fw, fh);
1936 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1937 break;
1939 case MotionNotify:
1940 if (started) {
1941 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
1943 dw = 0;
1944 dh = 0;
1946 orig_fx = fx;
1947 orig_fy = fy;
1948 orig_fw = fw;
1949 orig_fh = fh;
1951 if (res & LEFT)
1952 dw = orig_x - event.xmotion.x_root;
1953 else if (res & RIGHT)
1954 dw = event.xmotion.x_root - orig_x;
1955 if (res & UP)
1956 dh = orig_y - event.xmotion.y_root;
1957 else if (res & DOWN)
1958 dh = event.xmotion.y_root - orig_y;
1960 orig_x = event.xmotion.x_root;
1961 orig_y = event.xmotion.y_root;
1963 rw += dw;
1964 rh += dh;
1965 fw = rw;
1966 fh = rh - vert_border;
1967 wWindowConstrainSize(wwin, (unsigned int *)&fw, (unsigned int *)&fh);
1968 fh += vert_border;
1969 if (res & LEFT)
1970 fx = rx2 - fw + 1;
1971 else if (res & RIGHT)
1972 fx = rx1;
1973 if (res & UP)
1974 fy = ry2 - fh + 1;
1975 else if (res & DOWN)
1976 fy = ry1;
1977 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
1978 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1979 int tx, ty;
1980 Window junkw;
1981 int flags;
1983 XTranslateCoordinates(dpy, root, wwin->frame->core->window,
1984 orig_x, orig_y, &tx, &ty, &junkw);
1986 /* check if resizing through resizebar */
1987 if (is_resizebar)
1988 flags = RESIZEBAR;
1989 else
1990 flags = 0;
1992 if (is_resizebar && ((ev->xbutton.state & ShiftMask)
1993 || abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
1994 flags |= HCONSTRAIN;
1996 res = getResizeDirection(wwin, tx, ty,
1997 orig_x - event.xmotion.x_root,
1998 orig_y - event.xmotion.y_root, flags);
2000 if (res == (UP | LEFT))
2001 XChangeActivePointerGrab(dpy, ButtonMotionMask
2002 | ButtonReleaseMask | ButtonPressMask,
2003 wCursor[WCUR_TOPLEFTRESIZE], CurrentTime);
2004 else if (res == (UP | RIGHT))
2005 XChangeActivePointerGrab(dpy, ButtonMotionMask
2006 | ButtonReleaseMask | ButtonPressMask,
2007 wCursor[WCUR_TOPRIGHTRESIZE], CurrentTime);
2008 else if (res == (DOWN | LEFT))
2009 XChangeActivePointerGrab(dpy, ButtonMotionMask
2010 | ButtonReleaseMask | ButtonPressMask,
2011 wCursor[WCUR_BOTTOMLEFTRESIZE], CurrentTime);
2012 else if (res == (DOWN | RIGHT))
2013 XChangeActivePointerGrab(dpy, ButtonMotionMask
2014 | ButtonReleaseMask | ButtonPressMask,
2015 wCursor[WCUR_BOTTOMRIGHTRESIZE], CurrentTime);
2016 else if (res == DOWN || res == UP)
2017 XChangeActivePointerGrab(dpy, ButtonMotionMask
2018 | ButtonReleaseMask | ButtonPressMask,
2019 wCursor[WCUR_VERTICALRESIZE], CurrentTime);
2020 else if (res & (DOWN | UP))
2021 XChangeActivePointerGrab(dpy, ButtonMotionMask
2022 | ButtonReleaseMask | ButtonPressMask,
2023 wCursor[WCUR_VERTICALRESIZE], CurrentTime);
2024 else if (res & (LEFT | RIGHT))
2025 XChangeActivePointerGrab(dpy, ButtonMotionMask
2026 | ButtonReleaseMask | ButtonPressMask,
2027 wCursor[WCUR_HORIZONRESIZE], CurrentTime);
2029 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
2031 XGrabServer(dpy);
2033 /* Draw the resize frame for the first time. */
2034 mapGeometryDisplay(wwin, fx, fy, fw, fh);
2036 drawTransparentFrame(wwin, fx, fy, fw, fh);
2038 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2040 started = 1;
2042 if (started) {
2043 if (wPreferences.size_display == WDIS_FRAME_CENTER) {
2044 drawTransparentFrame(wwin, orig_fx, orig_fy, orig_fw, orig_fh);
2045 moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
2046 drawTransparentFrame(wwin, fx, fy, fw, fh);
2047 } else {
2048 drawTransparentFrame(wwin, orig_fx, orig_fy, orig_fw, orig_fh);
2049 drawTransparentFrame(wwin, fx, fy, fw, fh);
2051 if (fh != orig_fh || fw != orig_fw) {
2052 if (wPreferences.size_display == WDIS_NEW) {
2053 showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw,
2054 orig_fy + orig_fh, res);
2056 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2059 break;
2061 case ButtonPress:
2062 break;
2064 case ButtonRelease:
2065 if (event.xbutton.button != ev->xbutton.button)
2066 break;
2068 if (started) {
2069 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2071 drawTransparentFrame(wwin, fx, fy, fw, fh);
2073 XUngrabKeyboard(dpy, CurrentTime);
2074 WMUnmapWidget(scr->gview);
2075 XUngrabServer(dpy);
2077 if (wwin->client.width != fw) {
2078 wwin->flags.user_changed_width = 1;
2079 wwin->flags.maximized &= ~(MAX_HORIZONTAL | MAX_MAXIMUS);
2082 if (wwin->client.height != fh - vert_border) {
2083 wwin->flags.user_changed_height = 1;
2084 wwin->flags.maximized &= ~(MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS);
2087 wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
2089 #ifdef DEBUG
2090 puts("End resize window");
2091 #endif
2092 return;
2094 default:
2095 WMHandleEvent(&event);
2099 if (wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 && head != wGetHeadForWindow(wwin)) {
2100 wArrangeIcons(scr, True);
2102 #if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP)
2103 wWorkspaceResizeViewport(scr, scr->current_workspace);
2104 #endif
2107 #undef LEFT
2108 #undef RIGHT
2109 #undef HORIZONTAL
2110 #undef UP
2111 #undef DOWN
2112 #undef VERTICAL
2113 #undef HCONSTRAIN
2114 #undef RESIZEBAR
2116 void wUnselectWindows(WScreen * scr)
2118 WWindow *wwin;
2120 if (!scr->selected_windows)
2121 return;
2123 while (WMGetArrayItemCount(scr->selected_windows)) {
2124 wwin = WMGetFromArray(scr->selected_windows, 0);
2125 if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
2126 wIconSelect(wwin->icon);
2128 wSelectWindow(wwin, False);
2130 WMFreeArray(scr->selected_windows);
2131 scr->selected_windows = NULL;
2134 static void selectWindowsInside(WScreen * scr, int x1, int y1, int x2, int y2)
2136 WWindow *tmpw;
2138 /* select the windows and put them in the selected window list */
2139 tmpw = scr->focused_window;
2140 while (tmpw != NULL) {
2141 if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
2142 if ((tmpw->frame->workspace == scr->current_workspace || IS_OMNIPRESENT(tmpw))
2143 && (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1)
2144 && (tmpw->frame->core->width + tmpw->frame_x <= x2)
2145 && (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
2146 wSelectWindow(tmpw, True);
2149 tmpw = tmpw->prev;
2153 void wSelectWindows(WScreen * scr, XEvent * ev)
2155 XEvent event;
2156 Window root = scr->root_win;
2157 GC gc = scr->frame_gc;
2158 int xp = ev->xbutton.x_root;
2159 int yp = ev->xbutton.y_root;
2160 int w = 0, h = 0;
2161 int x = xp, y = yp;
2163 #ifdef DEBUG
2164 puts("Selecting windows");
2165 #endif
2166 if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
2167 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
2168 GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
2169 return;
2171 XGrabServer(dpy);
2173 wUnselectWindows(scr);
2175 XDrawRectangle(dpy, root, gc, xp, yp, w, h);
2176 while (1) {
2177 WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask | ButtonPressMask, &event);
2179 switch (event.type) {
2180 case MotionNotify:
2181 XDrawRectangle(dpy, root, gc, x, y, w, h);
2182 x = event.xmotion.x_root;
2183 if (x < xp) {
2184 w = xp - x;
2185 } else {
2186 w = x - xp;
2187 x = xp;
2189 y = event.xmotion.y_root;
2190 if (y < yp) {
2191 h = yp - y;
2192 } else {
2193 h = y - yp;
2194 y = yp;
2196 XDrawRectangle(dpy, root, gc, x, y, w, h);
2197 break;
2199 case ButtonPress:
2200 break;
2202 case ButtonRelease:
2203 if (event.xbutton.button != ev->xbutton.button)
2204 break;
2206 XDrawRectangle(dpy, root, gc, x, y, w, h);
2207 XUngrabServer(dpy);
2208 XUngrabPointer(dpy, CurrentTime);
2209 selectWindowsInside(scr, x, y, x + w, y + h);
2211 #ifdef DEBUG
2212 puts("End window selection");
2213 #endif
2214 return;
2216 default:
2217 WMHandleEvent(&event);
2218 break;
2223 void InteractivePlaceWindow(WWindow * wwin, int *x_ret, int *y_ret, unsigned width, unsigned height)
2225 WScreen *scr = wwin->screen_ptr;
2226 Window root = scr->root_win;
2227 int x, y, h = 0;
2228 XEvent event;
2229 KeyCode shiftl, shiftr;
2230 Window junkw;
2231 int junk;
2233 if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
2234 GrabModeAsync, GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
2235 *x_ret = 0;
2236 *y_ret = 0;
2237 return;
2239 if (HAS_TITLEBAR(wwin)) {
2240 h = WMFontHeight(scr->title_font) + (wPreferences.window_title_clearance +
2241 TITLEBAR_EXTEND_SPACE) * 2;
2242 height += h;
2244 if (HAS_RESIZEBAR(wwin)) {
2245 height += RESIZEBAR_HEIGHT;
2247 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
2248 XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk, (unsigned *)&junk);
2249 mapPositionDisplay(wwin, x - width / 2, y - h / 2, width, height);
2251 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2253 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
2254 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
2255 while (1) {
2256 WMMaskEvent(dpy, PointerMotionMask | ButtonPressMask | ExposureMask | KeyPressMask, &event);
2258 if (!checkMouseSamplingRate(&event))
2259 continue;
2261 switch (event.type) {
2262 case KeyPress:
2263 if ((event.xkey.keycode == shiftl)
2264 || (event.xkey.keycode == shiftr)) {
2265 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2266 cyclePositionDisplay(wwin, x - width / 2, y - h / 2, width, height);
2267 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2269 break;
2271 case MotionNotify:
2272 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2274 x = event.xmotion.x_root;
2275 y = event.xmotion.y_root;
2277 if (wPreferences.move_display == WDIS_FRAME_CENTER)
2278 moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
2280 showPosition(wwin, x - width / 2, y - h / 2);
2282 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2284 break;
2286 case ButtonPress:
2287 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2288 XSync(dpy, 0);
2289 *x_ret = x - width / 2;
2290 *y_ret = y - h / 2;
2291 XUngrabPointer(dpy, CurrentTime);
2292 XUngrabKeyboard(dpy, CurrentTime);
2293 /* get rid of the geometry window */
2294 WMUnmapWidget(scr->gview);
2295 return;
2297 default:
2298 WMHandleEvent(&event);
2299 break;