xinerama stuff for solaris
[wmaker-crm.git] / src / moveres.c
blobfe1def98ae794a0639c0dfc122629ea9d42ed1f9
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>
50 #ifdef KWM_HINTS
51 #include "kwm.h"
52 #endif
54 /* How many different types of geometry/position
55 display thingies are there? */
56 #define NUM_DISPLAYS 5
58 #define LEFT 1
59 #define RIGHT 2
60 #define HORIZONTAL (LEFT|RIGHT)
61 #define UP 4
62 #define DOWN 8
63 #define VERTICAL (UP|DOWN)
66 /* True if window currently has a border. This also includes borderless
67 * windows which are currently selected
69 #define HAS_BORDER(w) ((w)->flags.selected || !WFLAGP((w), no_border))
72 /****** Global Variables ******/
73 extern Time LastTimestamp;
75 extern Cursor wCursor[WCUR_LAST];
77 extern WPreferences wPreferences;
79 extern Atom _XA_WM_PROTOCOLS;
84 *----------------------------------------------------------------------
85 * checkMouseSamplingRate-
86 * For lowering the mouse motion sampling rate for machines where
87 * it's too high (SGIs). If it returns False then the event should be
88 * ignored.
89 *----------------------------------------------------------------------
91 static Bool
92 checkMouseSamplingRate(XEvent *ev)
94 static Time previousMotion = 0;
96 if (ev->type == MotionNotify) {
97 if (ev->xmotion.time - previousMotion < DELAY_BETWEEN_MOUSE_SAMPLING) {
98 return False;
99 } else {
100 previousMotion = ev->xmotion.time;
103 return True;
109 *----------------------------------------------------------------------
110 * moveGeometryDisplayCentered
112 * routine that moves the geometry/position window on scr so it is
113 * centered over the given coordinates (x,y). Also the window position
114 * is clamped so it stays on the screen at all times.
115 *----------------------------------------------------------------------
117 static void
118 moveGeometryDisplayCentered(WScreen *scr, int x, int y)
120 unsigned int w = WMWidgetWidth(scr->gview);
121 unsigned int h = WMWidgetHeight(scr->gview);
122 int x1 = 0, y1 = 0, x2 = scr->scr_width, y2 = scr->scr_height;
124 x -= w / 2;
125 y -= h / 2;
127 /* dead area check */
128 if (scr->xine_info.count) {
129 WMRect rect;
130 int head, flags;
132 rect.pos.x = x;
133 rect.pos.y = y;
134 rect.size.width = w;
135 rect.size.height = h;
137 head = wGetRectPlacementInfo(scr, rect, &flags);
139 if (flags & (XFLAG_DEAD | XFLAG_PARTIAL)) {
140 rect = wGetRectForHead(scr, head);
141 x1 = rect.pos.x;
142 y1 = rect.pos.y;
143 x2 = x1 + rect.size.width;
144 y2 = y1 + rect.size.height;
148 if (x < x1 + 1)
149 x = x1 + 1;
150 else if (x > (x2 - w))
151 x = x2 - w;
153 if (y < y1 + 1)
154 y = y1 + 1;
155 else if (y > (y2 - h))
156 y = y2 - h;
159 WMMoveWidget(scr->gview, x, y);
163 static void
164 showPosition(WWindow *wwin, int x, int y)
166 WScreen *scr = wwin->screen_ptr;
168 if (wPreferences.move_display == WDIS_NEW) {
169 #if 0
170 int width = wwin->frame->core->width;
171 int height = wwin->frame->core->height;
173 GC lgc = scr->line_gc;
174 XSetForeground(dpy, lgc, scr->line_pixel);
175 sprintf(num, "%i", x);
177 XDrawLine(dpy, scr->root_win, lgc, 0, y-1, scr->scr_width, y-1);
178 XDrawLine(dpy, scr->root_win, lgc, 0, y+height+2, scr->scr_width,
179 y+height+2);
180 XDrawLine(dpy, scr->root_win, lgc, x-1, 0, x-1, scr->scr_height);
181 XDrawLine(dpy, scr->root_win, lgc, x+width+2, 0, x+width+2,
182 scr->scr_height);
183 #endif
184 } else {
185 #ifdef VIRTUAL_DESKTOP
186 WSetGeometryViewShownPosition(scr->gview,
187 x + scr->workspaces[scr->current_workspace]->view_x,
188 y + scr->workspaces[scr->current_workspace]->view_y);
189 #else
190 WSetGeometryViewShownPosition(scr->gview, x, y);
191 #endif
196 static void
197 cyclePositionDisplay(WWindow *wwin, int x, int y, int w, int h)
199 WScreen *scr = wwin->screen_ptr;
200 WMRect rect;
202 wPreferences.move_display++;
203 wPreferences.move_display %= NUM_DISPLAYS;
205 if (wPreferences.move_display == WDIS_NEW) {
206 wPreferences.move_display++;
207 wPreferences.move_display %= NUM_DISPLAYS;
210 if (wPreferences.move_display == WDIS_NONE) {
211 WMUnmapWidget(scr->gview);
212 } else {
213 if (wPreferences.move_display == WDIS_CENTER) {
214 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
215 moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width/2,
216 rect.pos.y + rect.size.height/2);
217 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
218 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
219 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
220 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
221 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
223 WMMapWidget(scr->gview);
228 static void
229 mapPositionDisplay(WWindow *wwin, int x, int y, int w, int h)
231 WScreen *scr = wwin->screen_ptr;
232 WMRect rect;
234 if (wPreferences.move_display == WDIS_NEW
235 || wPreferences.move_display == WDIS_NONE) {
236 return;
237 } else if (wPreferences.move_display == WDIS_CENTER) {
238 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
239 moveGeometryDisplayCentered(scr,
240 rect.pos.x + rect.size.width/2,
241 rect.pos.y + rect.size.height/2);
242 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
243 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
244 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
245 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
246 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
248 WMMapWidget(scr->gview);
249 WSetGeometryViewShownPosition(scr->gview, x, y);
253 static void
254 showGeometry(WWindow *wwin, int x1, int y1, int x2, int y2, int direction)
256 WScreen *scr = wwin->screen_ptr;
257 Window root = scr->root_win;
258 GC gc = scr->line_gc, saveGC;
259 int ty, by, my, x, y, mx, s;
260 char num[16];
261 XSegment segment[4];
262 int fw, fh;
263 WMColor *color;
264 WMPixel pixel;
266 /* This seems necessary for some odd reason (too lazy to write x1-1 and
267 * x2-1 everywhere below in the code). But why only for x? */
268 x1--; x2--;
270 if (HAS_BORDER(wwin)) {
271 x1 += FRAME_BORDER_WIDTH;
272 x2 += FRAME_BORDER_WIDTH;
273 y1 += FRAME_BORDER_WIDTH;
274 y2 += FRAME_BORDER_WIDTH;
277 ty = y1 + wwin->frame->top_width;
278 by = y2 - wwin->frame->bottom_width;
280 if (wPreferences.size_display == WDIS_NEW) {
281 fw = WMWidthOfString(scr->tech_draw_font, "8888", 4);
282 fh = WMFontHeight(scr->tech_draw_font);
284 XSetForeground(dpy, gc, scr->line_pixel);
286 /* vertical geometry */
287 if (((direction & LEFT) && (x2 < scr->scr_width - fw)) || (x1 < fw)) {
288 x = x2;
289 s = -15;
290 } else {
291 x = x1;
292 s = 15;
294 my = (ty + by) / 2;
296 /* top arrow & end bar */
297 segment[0].x1 = x - (s + 6); segment[0].y1 = ty;
298 segment[0].x2 = x - (s - 10); segment[0].y2 = ty;
300 /* arrowhead */
301 segment[1].x1 = x - (s - 2); segment[1].y1 = ty + 1;
302 segment[1].x2 = x - (s - 5); segment[1].y2 = ty + 7;
304 segment[2].x1 = x - (s - 2); segment[2].y1 = ty + 1;
305 segment[2].x2 = x - (s + 1); segment[2].y2 = ty + 7;
307 /* line */
308 segment[3].x1 = x - (s - 2); segment[3].y1 = ty + 1;
309 segment[3].x2 = x - (s - 2); segment[3].y2 = my - fh/2 - 1;
311 XDrawSegments(dpy, root, gc, segment, 4);
313 /* bottom arrow & end bar */
314 segment[0].y1 = by;
315 segment[0].y2 = by;
317 /* arrowhead */
318 segment[1].y1 = by - 1;
319 segment[1].y2 = by - 7;
321 segment[2].y1 = by - 1;
322 segment[2].y2 = by - 7;
324 /* line */
325 segment[3].y1 = my + fh/2 + 2;
326 segment[3].y2 = by - 1;
328 XDrawSegments(dpy, root, gc, segment, 4);
330 snprintf(num, sizeof(num), "%i", (by - ty - wwin->normal_hints->base_height) /
331 wwin->normal_hints->height_inc);
332 fw = WMWidthOfString(scr->tech_draw_font, num, strlen(num));
334 /* XSetForeground(dpy, gc, WMColorPixel(scr->window_title_color[WS_UNFOCUSED])); */
336 color = WMBlackColor(scr->wmscreen);
337 saveGC = scr->wmscreen->drawStringGC;
338 pixel = color->color.pixel;
340 /* Display the height. */
342 /* // ugly hack */
343 color->color.pixel = scr->line_pixel;
344 scr->wmscreen->drawStringGC = gc;
345 WMDrawString(scr->wmscreen, root, color, scr->tech_draw_font,
346 x - s + 3 - fw/2, my - fh/2 + 1, num, strlen(num));
347 scr->wmscreen->drawStringGC = saveGC;
348 color->color.pixel = pixel;
350 XSetForeground(dpy, gc, scr->line_pixel);
351 /* horizontal geometry */
352 if (y1 < 15) {
353 y = y2;
354 s = -15;
355 } else {
356 y = y1;
357 s = 15;
359 mx = x1 + (x2 - x1)/2;
360 snprintf(num, sizeof(num), "%i", (x2 - x1 - wwin->normal_hints->base_width) /
361 wwin->normal_hints->width_inc);
362 fw = WMWidthOfString(scr->tech_draw_font, num, strlen(num));
364 /* left arrow & end bar */
365 segment[0].x1 = x1; segment[0].y1 = y - (s + 6);
366 segment[0].x2 = x1; segment[0].y2 = y - (s - 10);
368 /* arrowhead */
369 segment[1].x1 = x1 + 7; segment[1].y1 = y - (s + 1);
370 segment[1].x2 = x1 + 1; segment[1].y2 = y - (s - 2);
372 segment[2].x1 = x1 + 1; segment[2].y1 = y - (s - 2);
373 segment[2].x2 = x1 + 7; segment[2].y2 = y - (s - 5);
375 /* line */
376 segment[3].x1 = x1 + 1; segment[3].y1 = y - (s - 2);
377 segment[3].x2 = mx - fw/2 - 2; segment[3].y2 = y - (s - 2);
379 XDrawSegments(dpy, root, gc, segment, 4);
381 /* right arrow & end bar */
382 segment[0].x1 = x2 + 1;
383 segment[0].x2 = x2 + 1;
385 /* arrowhead */
386 segment[1].x1 = x2 - 6;
387 segment[1].x2 = x2;
389 segment[2].x1 = x2;
390 segment[2].x2 = x2 - 6;
392 /* line */
393 segment[3].x1 = mx + fw/2 + 2;
394 segment[3].x2 = x2;
396 XDrawSegments(dpy, root, gc, segment, 4);
398 /* XSetForeground(dpy, gc, WMColorPixel(scr->window_title_color[WS_UNFOCUSED])); */
400 /* Display the width. */
401 /* // ugly hack */
402 color->color.pixel = scr->line_pixel;
403 scr->wmscreen->drawStringGC = gc;
404 WMDrawString(scr->wmscreen, root, color, scr->tech_draw_font,
405 mx - fw/2 + 1, y - s - fh/2 + 1, num, strlen(num));
406 scr->wmscreen->drawStringGC = saveGC;
407 color->color.pixel = pixel;
408 WMReleaseColor(color);
409 } else {
410 WSetGeometryViewShownSize(scr->gview,
411 (x2 - x1 - wwin->normal_hints->base_width)
412 / wwin->normal_hints->width_inc,
413 (by - ty - wwin->normal_hints->base_height)
414 / wwin->normal_hints->height_inc);
419 static void
420 cycleGeometryDisplay(WWindow *wwin, int x, int y, int w, int h, int dir)
422 WScreen *scr = wwin->screen_ptr;
423 WMRect rect;
425 wPreferences.size_display++;
426 wPreferences.size_display %= NUM_DISPLAYS;
428 if (wPreferences.size_display == WDIS_NEW
429 || wPreferences.size_display == WDIS_NONE) {
430 WMUnmapWidget(scr->gview);
431 } else {
432 if (wPreferences.size_display == WDIS_CENTER) {
433 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
434 moveGeometryDisplayCentered(scr,
435 rect.pos.x + rect.size.width/2,
436 rect.pos.y + rect.size.height/2);
437 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
438 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
439 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
440 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
441 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
443 WMMapWidget(scr->gview);
444 showGeometry(wwin, x, y, x + w, y + h, dir);
449 static void
450 mapGeometryDisplay(WWindow *wwin, int x, int y, int w, int h)
452 WScreen *scr = wwin->screen_ptr;
453 WMRect rect;
455 if (wPreferences.size_display == WDIS_NEW
456 || wPreferences.size_display == WDIS_NONE)
457 return;
459 if (wPreferences.size_display == WDIS_CENTER) {
460 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
461 moveGeometryDisplayCentered(scr,
462 rect.pos.x + rect.size.width/2,
463 rect.pos.y + rect.size.height/2);
464 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
465 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
466 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
467 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
468 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
470 WMMapWidget(scr->gview);
471 showGeometry(wwin, x, y, x + w, y + h, 0);
476 static void
477 doWindowMove(WWindow *wwin, WMArray *array, int dx, int dy)
479 WWindow *tmpw;
480 WScreen *scr = wwin->screen_ptr;
481 int x, y;
483 if (!array || !WMGetArrayItemCount(array)) {
484 wWindowMove(wwin, wwin->frame_x + dx, wwin->frame_y + dy);
485 } else {
486 WMArrayIterator iter;
488 WM_ITERATE_ARRAY(array, tmpw, iter) {
489 x = tmpw->frame_x + dx;
490 y = tmpw->frame_y + dy;
492 #if 1 /* XXX: with xinerama patch was #if 0, check this */
493 /* don't let windows become unreachable */
495 if (x + (int)tmpw->frame->core->width < 20)
496 x = 20 - (int)tmpw->frame->core->width;
497 else if (x + 20 > scr->scr_width)
498 x = scr->scr_width - 20;
500 if (y + (int)tmpw->frame->core->height < 20)
501 y = 20 - (int)tmpw->frame->core->height;
502 else if (y + 20 > scr->scr_height)
503 y = scr->scr_height - 20;
504 #else
505 wScreenBringInside(scr, &x, &y,
506 (int)tmpw->frame->core->width,
507 (int)tmpw->frame->core->height);
508 #endif
510 wWindowMove(tmpw, x, y);
516 static void
517 drawTransparentFrame(WWindow *wwin, int x, int y, int width, int height)
519 Window root = wwin->screen_ptr->root_win;
520 GC gc = wwin->screen_ptr->frame_gc;
521 int h = 0;
522 int bottom = 0;
524 if (HAS_BORDER(wwin)) {
525 x += FRAME_BORDER_WIDTH;
526 y += FRAME_BORDER_WIDTH;
529 if (!WFLAGP(wwin, no_titlebar) && !wwin->flags.shaded) {
530 h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
532 if (!WFLAGP(wwin, no_resizebar) && !wwin->flags.shaded) {
533 /* Can't use wwin-frame->bottom_width because, in some cases
534 (e.g. interactive placement), frame does not point to anything. */
535 bottom = RESIZEBAR_HEIGHT;
537 XDrawRectangle(dpy, root, gc, x - 1, y - 1, width + 1, height + 1);
539 if (h > 0) {
540 XDrawLine(dpy, root, gc, x, y + h - 1, x + width, y + h - 1);
542 if (bottom > 0) {
543 XDrawLine(dpy, root, gc, x, y + height - bottom,
544 x + width, y + height - bottom);
549 static void
550 drawFrames(WWindow *wwin, WMArray *array, int dx, int dy)
552 WWindow *tmpw;
553 int scr_width = wwin->screen_ptr->scr_width;
554 int scr_height = wwin->screen_ptr->scr_height;
555 int x, y;
557 if (!array) {
559 x = wwin->frame_x + dx;
560 y = wwin->frame_y + dy;
562 drawTransparentFrame(wwin, x, y,
563 wwin->frame->core->width,
564 wwin->frame->core->height);
566 } else {
567 WMArrayIterator iter;
569 WM_ITERATE_ARRAY(array, tmpw, iter) {
570 x = tmpw->frame_x + dx;
571 y = tmpw->frame_y + dy;
573 /* don't let windows become unreachable */
574 #if 1 /* XXX: was 0 in XINERAMA patch, check */
575 if (x + (int)tmpw->frame->core->width < 20)
576 x = 20 - (int)tmpw->frame->core->width;
577 else if (x + 20 > scr_width)
578 x = scr_width - 20;
580 if (y + (int)tmpw->frame->core->height < 20)
581 y = 20 - (int)tmpw->frame->core->height;
582 else if (y + 20 > scr_height)
583 y = scr_height - 20;
585 #else
586 wScreenBringInside(wwin->screen_ptr, &x, &y,
587 (int)tmpw->frame->core->width,
588 (int)tmpw->frame->core->height);
589 #endif
591 drawTransparentFrame(tmpw, x, y, tmpw->frame->core->width,
592 tmpw->frame->core->height);
599 static void
600 flushMotion()
602 XEvent ev;
604 XSync(dpy, False);
605 while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
609 static void
610 crossWorkspace(WScreen *scr, WWindow *wwin, int opaque_move,
611 int new_workspace, int rewind)
613 /* do not let window be unmapped */
614 if (opaque_move) {
615 wwin->flags.changing_workspace = 1;
616 wWindowChangeWorkspace(wwin, new_workspace);
618 /* go to new workspace */
619 wWorkspaceChange(scr, new_workspace);
621 wwin->flags.changing_workspace = 0;
623 if (rewind)
624 XWarpPointer(dpy, None, None, 0, 0, 0, 0, scr->scr_width - 20, 0);
625 else
626 XWarpPointer(dpy, None, None, 0, 0, 0, 0, -(scr->scr_width - 20), 0);
628 flushMotion();
630 if (!opaque_move) {
631 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
632 |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
633 GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
640 typedef struct {
641 /* arrays of WWindows sorted by the respective border position */
642 WWindow **topList; /* top border */
643 WWindow **leftList; /* left border */
644 WWindow **rightList; /* right border */
645 WWindow **bottomList; /* bottom border */
646 int count;
648 /* index of window in the above lists indicating the relative position
649 * of the window with the others */
650 int topIndex;
651 int leftIndex;
652 int rightIndex;
653 int bottomIndex;
655 int rubCount; /* for workspace switching */
657 int winWidth, winHeight; /* width/height of the window */
658 int realX, realY; /* actual position of the window */
659 int calcX, calcY; /* calculated position of window */
660 int omouseX, omouseY; /* old mouse position */
661 int mouseX, mouseY; /* last known position of the pointer */
662 } MoveData;
664 #define WTOP(w) (w)->frame_y
665 #define WLEFT(w) (w)->frame_x
666 #define WRIGHT(w) ((w)->frame_x + (int)(w)->frame->core->width - 1 + \
667 (HAS_BORDER(w) ? 2*FRAME_BORDER_WIDTH : 0))
668 #define WBOTTOM(w) ((w)->frame_y + (int)(w)->frame->core->height - 1 + \
669 (HAS_BORDER(w) ? 2*FRAME_BORDER_WIDTH : 0))
671 static int
672 compareWTop(const void *a, const void *b)
674 WWindow *wwin1 = *(WWindow**)a;
675 WWindow *wwin2 = *(WWindow**)b;
677 if (WTOP(wwin1) > WTOP(wwin2))
678 return -1;
679 else if (WTOP(wwin1) < WTOP(wwin2))
680 return 1;
681 else
682 return 0;
686 static int
687 compareWLeft(const void *a, const void *b)
689 WWindow *wwin1 = *(WWindow**)a;
690 WWindow *wwin2 = *(WWindow**)b;
692 if (WLEFT(wwin1) > WLEFT(wwin2))
693 return -1;
694 else if (WLEFT(wwin1) < WLEFT(wwin2))
695 return 1;
696 else
697 return 0;
701 static int
702 compareWRight(const void *a, const void *b)
704 WWindow *wwin1 = *(WWindow**)a;
705 WWindow *wwin2 = *(WWindow**)b;
707 if (WRIGHT(wwin1) < WRIGHT(wwin2))
708 return -1;
709 else if (WRIGHT(wwin1) > WRIGHT(wwin2))
710 return 1;
711 else
712 return 0;
717 static int
718 compareWBottom(const void *a, const void *b)
720 WWindow *wwin1 = *(WWindow**)a;
721 WWindow *wwin2 = *(WWindow**)b;
723 if (WBOTTOM(wwin1) < WBOTTOM(wwin2))
724 return -1;
725 else if (WBOTTOM(wwin1) > WBOTTOM(wwin2))
726 return 1;
727 else
728 return 0;
732 static void
733 updateResistance(WWindow *wwin, MoveData *data, int newX, int newY)
735 int i;
736 int newX2 = newX + data->winWidth;
737 int newY2 = newY + data->winHeight;
738 Bool ok = False;
740 if (newX < data->realX) {
741 if (data->rightIndex > 0
742 && newX < WRIGHT(data->rightList[data->rightIndex-1])) {
743 ok = True;
744 } else if (data->leftIndex <= data->count-1
745 && newX2 <= WLEFT(data->leftList[data->leftIndex])) {
746 ok = True;
748 } else if (newX > data->realX) {
749 if (data->leftIndex > 0
750 && newX2 > WLEFT(data->leftList[data->leftIndex-1])) {
751 ok = True;
752 } else if (data->rightIndex <= data->count-1
753 && newX >= WRIGHT(data->rightList[data->rightIndex])) {
754 ok = True;
758 if (!ok) {
759 if (newY < data->realY) {
760 if (data->bottomIndex > 0
761 && newY < WBOTTOM(data->bottomList[data->bottomIndex-1])) {
762 ok = True;
763 } else if (data->topIndex <= data->count-1
764 && newY2 <= WTOP(data->topList[data->topIndex])) {
765 ok = True;
767 } else if (newY > data->realY) {
768 if (data->topIndex > 0
769 && newY2 > WTOP(data->topList[data->topIndex-1])) {
770 ok = True;
771 } else if (data->bottomIndex <= data->count-1
772 && newY >= WBOTTOM(data->bottomList[data->bottomIndex])) {
773 ok = True;
778 if (!ok)
779 return;
781 /* TODO: optimize this */
782 if (data->realY < WBOTTOM(data->bottomList[0])) {
783 data->bottomIndex = 0;
785 if (data->realX < WRIGHT(data->rightList[0])) {
786 data->rightIndex = 0;
788 if ((data->realX + data->winWidth) > WLEFT(data->leftList[0])) {
789 data->leftIndex = 0;
791 if ((data->realY + data->winHeight) > WTOP(data->topList[0])) {
792 data->topIndex = 0;
794 for (i = 0; i < data->count; i++) {
795 if (data->realY > WBOTTOM(data->bottomList[i])) {
796 data->bottomIndex = i + 1;
798 if (data->realX > WRIGHT(data->rightList[i])) {
799 data->rightIndex = i + 1;
801 if ((data->realX + data->winWidth) < WLEFT(data->leftList[i])) {
802 data->leftIndex = i + 1;
804 if ((data->realY + data->winHeight) < WTOP(data->topList[i])) {
805 data->topIndex = i + 1;
811 static void
812 freeMoveData(MoveData *data)
814 if (data->topList)
815 wfree(data->topList);
816 if (data->leftList)
817 wfree(data->leftList);
818 if (data->rightList)
819 wfree(data->rightList);
820 if (data->bottomList)
821 wfree(data->bottomList);
825 static void
826 updateMoveData(WWindow *wwin, MoveData *data)
828 WScreen *scr = wwin->screen_ptr;
829 WWindow *tmp;
830 int i;
832 data->count = 0;
833 tmp = scr->focused_window;
834 while (tmp) {
835 if (tmp != wwin && scr->current_workspace == tmp->frame->workspace
836 && !tmp->flags.miniaturized
837 && !tmp->flags.hidden
838 && !tmp->flags.obscured
839 && !WFLAGP(tmp, sunken)) {
840 data->topList[data->count] = tmp;
841 data->leftList[data->count] = tmp;
842 data->rightList[data->count] = tmp;
843 data->bottomList[data->count] = tmp;
844 data->count++;
846 tmp = tmp->prev;
849 if (data->count == 0) {
850 data->topIndex = 0;
851 data->leftIndex = 0;
852 data->rightIndex = 0;
853 data->bottomIndex = 0;
854 return;
857 /* order from closest to the border of the screen to farthest */
859 qsort(data->topList, data->count, sizeof(WWindow**), compareWTop);
860 qsort(data->leftList, data->count, sizeof(WWindow**), compareWLeft);
861 qsort(data->rightList, data->count, sizeof(WWindow**), compareWRight);
862 qsort(data->bottomList, data->count, sizeof(WWindow**), compareWBottom);
864 /* figure the position of the window relative to the others */
866 data->topIndex = -1;
867 data->leftIndex = -1;
868 data->rightIndex = -1;
869 data->bottomIndex = -1;
871 if (WTOP(wwin) < WBOTTOM(data->bottomList[0])) {
872 data->bottomIndex = 0;
874 if (WLEFT(wwin) < WRIGHT(data->rightList[0])) {
875 data->rightIndex = 0;
877 if (WRIGHT(wwin) > WLEFT(data->leftList[0])) {
878 data->leftIndex = 0;
880 if (WBOTTOM(wwin) > WTOP(data->topList[0])) {
881 data->topIndex = 0;
883 for (i = 0; i < data->count; i++) {
884 if (WTOP(wwin) >= WBOTTOM(data->bottomList[i])) {
885 data->bottomIndex = i + 1;
887 if (WLEFT(wwin) >= WRIGHT(data->rightList[i])) {
888 data->rightIndex = i + 1;
890 if (WRIGHT(wwin) <= WLEFT(data->leftList[i])) {
891 data->leftIndex = i + 1;
893 if (WBOTTOM(wwin) <= WTOP(data->topList[i])) {
894 data->topIndex = i + 1;
900 static void
901 initMoveData(WWindow *wwin, MoveData *data)
903 int i;
904 WWindow *tmp;
906 memset(data, 0, sizeof(MoveData));
908 for (i = 0, tmp = wwin->screen_ptr->focused_window;
909 tmp != NULL;
910 tmp = tmp->prev, i++);
912 if (i > 1) {
913 data->topList = wmalloc(sizeof(WWindow*) * i);
914 data->leftList = wmalloc(sizeof(WWindow*) * i);
915 data->rightList = wmalloc(sizeof(WWindow*) * i);
916 data->bottomList = wmalloc(sizeof(WWindow*) * i);
918 updateMoveData(wwin, data);
921 data->realX = wwin->frame_x;
922 data->realY = wwin->frame_y;
923 data->calcX = wwin->frame_x;
924 data->calcY = wwin->frame_y;
926 data->winWidth = wwin->frame->core->width +
927 (HAS_BORDER(wwin) ? 2*FRAME_BORDER_WIDTH : 0);
928 data->winHeight = wwin->frame->core->height +
929 (HAS_BORDER(wwin) ? 2*FRAME_BORDER_WIDTH : 0);
933 static Bool
934 checkWorkspaceChange(WWindow *wwin, MoveData *data, Bool opaqueMove)
936 WScreen *scr = wwin->screen_ptr;
937 Bool changed = False;
939 if (data->mouseX <= 1) {
940 if (scr->current_workspace > 0) {
942 crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace - 1,
943 True);
944 changed = True;
945 data->rubCount = 0;
947 } else if (scr->current_workspace == 0 && wPreferences.ws_cycle) {
949 crossWorkspace(scr, wwin, opaqueMove, scr->workspace_count - 1,
950 True);
951 changed = True;
952 data->rubCount = 0;
954 } else if (data->mouseX >= scr->scr_width - 2) {
956 if (scr->current_workspace == scr->workspace_count - 1) {
958 if (wPreferences.ws_cycle
959 || scr->workspace_count == MAX_WORKSPACES) {
961 crossWorkspace(scr, wwin, opaqueMove, 0, False);
962 changed = True;
963 data->rubCount = 0;
965 /* if user insists on trying to go to next workspace even when
966 * it's already the last, create a new one */
967 else if (data->omouseX == data->mouseX
968 && wPreferences.ws_advance) {
970 /* detect user "rubbing" the window against the edge */
971 if (data->rubCount > 0
972 && data->omouseY - data->mouseY > MOVE_THRESHOLD) {
974 data->rubCount = -(data->rubCount + 1);
976 } else if (data->rubCount <= 0
977 && data->mouseY - data->omouseY > MOVE_THRESHOLD) {
979 data->rubCount = -data->rubCount + 1;
982 /* create a new workspace */
983 if (abs(data->rubCount) > 2) {
984 /* go to next workspace */
985 wWorkspaceNew(scr);
987 crossWorkspace(scr, wwin, opaqueMove,
988 scr->current_workspace+1, False);
989 changed = True;
990 data->rubCount = 0;
992 } else if (scr->current_workspace < scr->workspace_count) {
994 /* go to next workspace */
995 crossWorkspace(scr, wwin, opaqueMove,
996 scr->current_workspace+1, False);
997 changed = True;
998 data->rubCount = 0;
1000 } else {
1001 data->rubCount = 0;
1004 return changed;
1008 static void
1009 updateWindowPosition(WWindow *wwin, MoveData *data, Bool doResistance,
1010 Bool opaqueMove, int newMouseX, int newMouseY)
1012 WScreen *scr = wwin->screen_ptr;
1013 int dx, dy; /* how much mouse moved */
1014 int winL, winR, winT, winB; /* requested new window position */
1015 int newX, newY; /* actual new window position */
1016 Bool hresist, vresist;
1017 Bool updateIndex;
1018 Bool attract;
1020 hresist = False;
1021 vresist = False;
1023 updateIndex = False;
1025 /* check the direction of the movement */
1026 dx = newMouseX - data->mouseX;
1027 dy = newMouseY - data->mouseY;
1029 data->omouseX = data->mouseX;
1030 data->omouseY = data->mouseY;
1031 data->mouseX = newMouseX;
1032 data->mouseY = newMouseY;
1034 winL = data->calcX + dx;
1035 winR = data->calcX + data->winWidth + dx;
1036 winT = data->calcY + dy;
1037 winB = data->calcY + data->winHeight + dy;
1039 newX = data->realX;
1040 newY = data->realY;
1042 if (doResistance) {
1043 int l_edge, r_edge;
1044 int edge_l, edge_r;
1045 int t_edge, b_edge;
1046 int edge_t, edge_b;
1047 int resist;
1049 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1050 attract = wPreferences.attract;
1051 /* horizontal movement: check horizontal edge resistances */
1052 if (dx || dy) {
1053 WMRect rect;
1054 int i;
1055 /* window is the leftmost window: check against screen edge */
1057 /* Add inter head resistance 1/2 (if needed) */
1058 rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
1060 l_edge = WMAX(scr->totalUsableArea.x1, rect.pos.x);
1061 edge_l = l_edge - resist;
1062 edge_r = WMIN(scr->totalUsableArea.x2, rect.pos.x + rect.size.width);
1063 r_edge = edge_r + resist;
1065 /* 1 */
1066 if ((data->rightIndex >= 0) && (data->rightIndex <= data->count)) {
1067 WWindow *looprw;
1069 for (i = data->rightIndex - 1; i >= 0; i--) {
1070 looprw = data->rightList[i];
1071 if (!(data->realY > WBOTTOM(looprw)
1072 || (data->realY + data->winHeight) < WTOP(looprw))) {
1073 if (attract
1074 || ((data->realX < (WRIGHT(looprw) + 2)) && dx < 0)) {
1075 l_edge = WRIGHT(looprw) + 1;
1076 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1078 break;
1082 if (attract) {
1083 for (i = data->rightIndex; i < data->count; i++) {
1084 looprw = data->rightList[i];
1085 if(!(data->realY > WBOTTOM(looprw)
1086 || (data->realY + data->winHeight) < WTOP(looprw))) {
1087 r_edge = WRIGHT(looprw) + 1;
1088 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1089 break;
1095 if ((data->leftIndex >= 0) && (data->leftIndex <= data->count)) {
1096 WWindow *looprw;
1098 for (i = data->leftIndex - 1; i >= 0; i--) {
1099 looprw = data->leftList[i];
1100 if (!(data->realY > WBOTTOM(looprw)
1101 || (data->realY + data->winHeight) < WTOP(looprw))) {
1102 if (attract
1103 || (((data->realX + data->winWidth) > (WLEFT(looprw) - 1)) && dx > 0)) {
1104 edge_r = WLEFT(looprw);
1105 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1107 break;
1111 if (attract)
1112 for (i = data->leftIndex; i < data->count; i++) {
1113 looprw = data->leftList[i];
1114 if(!(data->realY > WBOTTOM(looprw)
1115 || (data->realY + data->winHeight) < WTOP(looprw))) {
1116 edge_l = WLEFT(looprw);
1117 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1118 break;
1124 printf("%d %d\n",winL,winR);
1125 printf("l_ %d r_ %d _l %d _r %d\n",l_edge,r_edge,edge_l,edge_r);
1128 if ((winL - l_edge) < (r_edge - winL)) {
1129 if (resist > 0) {
1130 if ((attract && winL <= l_edge + resist && winL >= l_edge - resist)
1131 || (dx < 0 && winL <= l_edge && winL >= l_edge - resist)) {
1132 newX = l_edge;
1133 hresist = True;
1136 } else {
1137 if (resist > 0 && attract && winL >= r_edge - resist && winL <= r_edge + resist) {
1138 newX = r_edge;
1139 hresist = True;
1143 if ((winR - edge_l) < (edge_r - winR)) {
1144 if (resist > 0 && attract && winR <= edge_l + resist && winR >= edge_l - resist) {
1145 newX = edge_l - data->winWidth;
1146 hresist = True;
1148 } else {
1149 if (resist > 0) {
1150 if ((attract && winR >= edge_r - resist && winR <= edge_r + resist)
1151 || (dx > 0 && winR >= edge_r && winR <= edge_r + resist)) {
1152 newX = edge_r - data->winWidth;
1153 hresist = True;
1158 /* VeRT */
1159 /* Add inter head resistance 2/2 (if needed) */
1160 t_edge = WMAX(scr->totalUsableArea.y1, rect.pos.y);
1161 edge_t = t_edge - resist;
1162 edge_b = WMIN(scr->totalUsableArea.y2, rect.pos.y + rect.size.height);
1163 b_edge = edge_b + resist;
1165 if ((data->bottomIndex >= 0) && (data->bottomIndex <= data->count)) {
1166 WWindow *looprw;
1168 for (i = data->bottomIndex - 1; i >= 0; i--) {
1169 looprw = data->bottomList[i];
1170 if (!(data->realX > WRIGHT(looprw)
1171 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1172 if (attract
1173 || ((data->realY < (WBOTTOM(looprw) + 2)) && dy < 0)) {
1174 t_edge = WBOTTOM(looprw) + 1;
1175 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1177 break;
1181 if (attract) {
1182 for (i = data->bottomIndex; i < data->count; i++) {
1183 looprw = data->bottomList[i];
1184 if(!(data->realX > WRIGHT(looprw)
1185 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1186 b_edge = WBOTTOM(looprw) + 1;
1187 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1188 break;
1194 if ((data->topIndex >= 0) && (data->topIndex <= data->count)) {
1195 WWindow *looprw;
1197 for (i = data->topIndex - 1; i >= 0; i--) {
1198 looprw = data->topList[i];
1199 if (!(data->realX > WRIGHT(looprw)
1200 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1201 if (attract
1202 || (((data->realY + data->winHeight) > (WTOP(looprw) - 1)) && dy > 0)) {
1203 edge_b = WTOP(looprw);
1204 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1206 break;
1210 if (attract)
1211 for (i = data->topIndex; i < data->count; i++) {
1212 looprw = data->topList[i];
1213 if(!(data->realX > WRIGHT(looprw)
1214 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1215 edge_t = WTOP(looprw);
1216 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1217 break;
1222 if ((winT - t_edge) < (b_edge - winT)) {
1223 if (resist > 0) {
1224 if ((attract && winT <= t_edge + resist && winT >= t_edge - resist)
1225 || (dy < 0 && winT <= t_edge && winT >= t_edge - resist)) {
1226 newY = t_edge;
1227 vresist = True;
1231 else {
1232 if (resist > 0 && attract && winT >= b_edge - resist && winT <= b_edge + resist) {
1233 newY = b_edge;
1234 vresist = True;
1238 if ((winB - edge_t) < (edge_b - winB)) {
1239 if (resist > 0 && attract && winB <= edge_t + resist && winB >= edge_t - resist) {
1240 newY = edge_t - data->winHeight;
1241 vresist = True;
1244 else {
1245 if (resist > 0) {
1246 if ((attract && winB >= edge_b - resist && winB <= edge_b + resist)
1247 || (dy > 0 && winB >= edge_b && winB <= edge_b + resist)) {
1248 newY = edge_b - data->winHeight;
1249 vresist = True;
1254 /* END VeRT */
1258 /* update window position */
1259 data->calcX += dx;
1260 data->calcY += dy;
1262 if (((dx > 0 && data->calcX - data->realX > 0)
1263 || (dx < 0 && data->calcX - data->realX < 0)) && !hresist)
1264 newX = data->calcX;
1266 if (((dy > 0 && data->calcY - data->realY > 0)
1267 || (dy < 0 && data->calcY - data->realY < 0)) && !vresist)
1268 newY = data->calcY;
1270 if (data->realX != newX || data->realY != newY) {
1272 if (wPreferences.move_display == WDIS_NEW
1273 && !scr->selected_windows) {
1274 showPosition(wwin, data->realX, data->realY);
1276 if (opaqueMove) {
1277 doWindowMove(wwin, scr->selected_windows,
1278 newX - wwin->frame_x,
1279 newY - wwin->frame_y);
1280 } else {
1281 /* erase frames */
1282 drawFrames(wwin, scr->selected_windows,
1283 data->realX - wwin->frame_x,
1284 data->realY - wwin->frame_y);
1287 if (!scr->selected_windows
1288 && wPreferences.move_display == WDIS_FRAME_CENTER) {
1290 moveGeometryDisplayCentered(scr, newX + data->winWidth/2,
1291 newY + data->winHeight/2);
1294 if (!opaqueMove) {
1295 /* draw frames */
1296 drawFrames(wwin, scr->selected_windows,
1297 newX - wwin->frame_x,
1298 newY - wwin->frame_y);
1301 if (!scr->selected_windows) {
1302 showPosition(wwin, newX, newY);
1307 /* recalc relative window position */
1308 if (doResistance && (data->realX != newX || data->realY != newY)) {
1309 updateResistance(wwin, data, newX, newY);
1312 data->realX = newX;
1313 data->realY = newY;
1317 #define _KS KEY_CONTROL_WINDOW_WEIGHT
1320 wKeyboardMoveResizeWindow(WWindow *wwin)
1322 WScreen *scr = wwin->screen_ptr;
1323 Window root = scr->root_win;
1324 XEvent event;
1325 int w = wwin->frame->core->width;
1326 int h = wwin->frame->core->height;
1327 int scr_width = wwin->screen_ptr->scr_width;
1328 int scr_height = wwin->screen_ptr->scr_height;
1329 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1330 int src_x = wwin->frame_x;
1331 int src_y = wwin->frame_y;
1332 int done,off_x,off_y,ww,wh;
1333 int kspeed = _KS;
1334 Time lastTime = 0;
1335 KeySym keysym=NoSymbol;
1336 int moment=0;
1337 KeyCode shiftl,shiftr,ctrll,ctrlmode;
1339 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1340 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1341 ctrll = XKeysymToKeycode(dpy, XK_Control_L);
1342 ctrlmode=done=off_x=off_y=0;
1344 XSync(dpy, False);
1345 wusleep(10000);
1346 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1348 if (!wwin->flags.selected) {
1349 wUnselectWindows(scr);
1351 XGrabServer(dpy);
1352 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
1353 |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
1354 GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime);
1356 if (wwin->flags.shaded || scr->selected_windows) {
1357 if(scr->selected_windows)
1358 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1359 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1360 if(!scr->selected_windows)
1361 mapPositionDisplay(wwin, src_x, src_y, w, h);
1362 } else {
1363 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1365 ww=w;
1366 wh=h;
1367 while(1) {
1369 looper.ox=off_x;
1370 looper.oy=off_y;
1372 do {
1373 WMMaskEvent(dpy, KeyPressMask | ButtonReleaseMask
1374 | ButtonPressMask | ExposureMask, &event);
1375 if (event.type == Expose) {
1376 WMHandleEvent(&event);
1378 } while (event.type == Expose);
1381 if (wwin->flags.shaded || scr->selected_windows) {
1382 if(scr->selected_windows)
1383 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1384 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1385 /*** I HATE EDGE RESISTANCE - ]d ***/
1387 else {
1388 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
1391 if(ctrlmode)
1392 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
1394 XUngrabServer(dpy);
1395 XSync(dpy, False);
1397 switch (event.type) {
1398 case KeyPress:
1399 /* accelerate */
1400 if (event.xkey.time - lastTime > 50) {
1401 kspeed/=(1 + (event.xkey.time - lastTime)/100);
1402 } else {
1403 if (kspeed < 20) {
1404 kspeed++;
1407 if (kspeed < _KS) kspeed = _KS;
1408 lastTime = event.xkey.time;
1410 if (event.xkey.state & ControlMask && !wwin->flags.shaded) {
1411 ctrlmode=1;
1412 wUnselectWindows(scr);
1414 else {
1415 ctrlmode=0;
1417 if (event.xkey.keycode == shiftl || event.xkey.keycode == shiftr) {
1418 if (ctrlmode)
1419 cycleGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh, 0);
1420 else
1421 cyclePositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
1423 else {
1425 keysym = XLookupKeysym(&event.xkey, 0);
1426 switch (keysym) {
1427 case XK_Return:
1428 done=2;
1429 break;
1430 case XK_Escape:
1431 done=1;
1432 break;
1433 case XK_Up:
1434 #ifdef XK_KP_Up
1435 case XK_KP_Up:
1436 #endif
1437 case XK_k:
1438 if (ctrlmode){
1439 if (moment != UP)
1440 h = wh;
1441 h-=kspeed;
1442 moment = UP;
1443 if (h < 1) h = 1;
1445 else off_y-=kspeed;
1446 break;
1447 case XK_Down:
1448 #ifdef XK_KP_Down
1449 case XK_KP_Down:
1450 #endif
1451 case XK_j:
1452 if (ctrlmode){
1453 if (moment != DOWN)
1454 h = wh;
1455 h+=kspeed;
1456 moment = DOWN;
1458 else off_y+=kspeed;
1459 break;
1460 case XK_Left:
1461 #ifdef XK_KP_Left
1462 case XK_KP_Left:
1463 #endif
1464 case XK_h:
1465 if (ctrlmode) {
1466 if (moment != LEFT)
1467 w = ww;
1468 w-=kspeed;
1469 if (w < 1) w = 1;
1470 moment = LEFT;
1472 else off_x-=kspeed;
1473 break;
1474 case XK_Right:
1475 #ifdef XK_KP_Right
1476 case XK_KP_Right:
1477 #endif
1478 case XK_l:
1479 if (ctrlmode) {
1480 if (moment != RIGHT)
1481 w = ww;
1482 w+=kspeed;
1483 moment = RIGHT;
1485 else off_x+=kspeed;
1486 break;
1489 ww=w;wh=h;
1490 wh-=vert_border;
1491 wWindowConstrainSize(wwin, &ww, &wh);
1492 wh+=vert_border;
1494 if (wPreferences.ws_cycle){
1495 if (src_x + off_x + ww < 20){
1496 if(!scr->current_workspace) {
1497 wWorkspaceChange(scr, scr->workspace_count-1);
1499 else wWorkspaceChange(scr, scr->current_workspace-1);
1500 off_x += scr_width;
1502 else if (src_x + off_x + 20 > scr_width){
1503 if(scr->current_workspace == scr->workspace_count-1) {
1504 wWorkspaceChange(scr, 0);
1506 else wWorkspaceChange(scr, scr->current_workspace+1);
1507 off_x -= scr_width;
1510 else {
1511 if (src_x + off_x + ww < 20)
1512 off_x = 20 - ww - src_x;
1513 else if (src_x + off_x + 20 > scr_width)
1514 off_x = scr_width - 20 - src_x;
1517 if (src_y + off_y + wh < 20) {
1518 off_y = 20 - wh - src_y;
1520 else if (src_y + off_y + 20 > scr_height) {
1521 off_y = scr_height - 20 - src_y;
1524 break;
1525 case ButtonPress:
1526 case ButtonRelease:
1527 done=1;
1528 break;
1529 case Expose:
1530 WMHandleEvent(&event);
1531 while (XCheckTypedEvent(dpy, Expose, &event)) {
1532 WMHandleEvent(&event);
1534 break;
1536 default:
1537 WMHandleEvent(&event);
1538 break;
1541 XGrabServer(dpy);
1542 /*xxx*/
1544 if (wwin->flags.shaded && !scr->selected_windows){
1545 moveGeometryDisplayCentered(scr, src_x+off_x + w/2, src_y+off_y + h/2);
1546 } else {
1547 if (ctrlmode) {
1548 WMUnmapWidget(scr->gview);
1549 mapGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
1550 } else if(!scr->selected_windows) {
1551 WMUnmapWidget(scr->gview);
1552 mapPositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
1556 if (wwin->flags.shaded || scr->selected_windows) {
1557 if (scr->selected_windows)
1558 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1559 else
1560 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1561 } else {
1562 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
1566 if (ctrlmode) {
1567 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
1568 } else if(!scr->selected_windows)
1569 showPosition(wwin, src_x+off_x, src_y+off_y);
1570 /**/
1572 if (done) {
1573 scr->keymove_tick=0;
1575 WMDeleteTimerWithClientData(&looper);
1577 if (wwin->flags.shaded || scr->selected_windows) {
1578 if(scr->selected_windows)
1579 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1580 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1582 else {
1583 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
1586 if (ctrlmode) {
1587 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
1588 WMUnmapWidget(scr->gview);
1589 } else
1590 WMUnmapWidget(scr->gview);
1592 XUngrabKeyboard(dpy, CurrentTime);
1593 XUngrabPointer(dpy, CurrentTime);
1594 XUngrabServer(dpy);
1596 if(done==2) {
1597 if (wwin->flags.shaded || scr->selected_windows) {
1598 if (!scr->selected_windows) {
1599 wWindowMove(wwin, src_x+off_x, src_y+off_y);
1600 wWindowSynthConfigureNotify(wwin);
1601 } else {
1602 WMArrayIterator iter;
1603 WWindow *foo;
1605 doWindowMove(wwin, scr->selected_windows, off_x, off_y);
1607 WM_ITERATE_ARRAY(scr->selected_windows, foo, iter) {
1608 wWindowSynthConfigureNotify(foo);
1611 } else {
1612 if (wwin->client.width != ww)
1613 wwin->flags.user_changed_width = 1;
1615 if (wwin->client.height != wh - vert_border)
1616 wwin->flags.user_changed_height = 1;
1618 wWindowConfigure(wwin, src_x+off_x, src_y+off_y,
1619 ww, wh - vert_border);
1620 wWindowSynthConfigureNotify(wwin);
1622 wWindowChangeWorkspace(wwin, scr->current_workspace);
1623 wSetFocusTo(scr, wwin);
1625 return 1;
1632 *----------------------------------------------------------------------
1633 * wMouseMoveWindow--
1634 * Move the named window and the other selected ones (if any),
1635 * interactively. Also shows the position of the window, if only one
1636 * window is being moved.
1637 * If the window is not on the selected window list, the selected
1638 * windows are deselected.
1639 * If shift is pressed during the operation, the position display
1640 * is changed to another type.
1642 * Returns:
1643 * True if the window was moved, False otherwise.
1645 * Side effects:
1646 * The window(s) position is changed, and the client(s) are
1647 * notified about that.
1648 * The position display configuration may be changed.
1649 *----------------------------------------------------------------------
1652 wMouseMoveWindow(WWindow *wwin, XEvent *ev)
1654 WScreen *scr = wwin->screen_ptr;
1655 XEvent event;
1656 Window root = scr->root_win;
1657 KeyCode shiftl, shiftr;
1658 Bool done = False;
1659 int started = 0;
1660 int warped = 0;
1661 /* This needs not to change while moving, else bad things can happen */
1662 int opaqueMove = wPreferences.opaque_move;
1663 MoveData moveData;
1664 #ifdef GHOST_WINDOW_MOVE
1665 RImage *rimg;
1667 rimg = InitGhostWindowMove(scr);
1668 #endif
1671 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1672 XSetWindowAttributes attr;
1674 attr.save_under = True;
1675 XChangeWindowAttributes(dpy, wwin->frame->core->window,
1676 CWSaveUnder, &attr);
1680 initMoveData(wwin, &moveData);
1682 moveData.mouseX = ev->xmotion.x_root;
1683 moveData.mouseY = ev->xmotion.y_root;
1685 if (!wwin->flags.selected) {
1686 /* this window is not selected, unselect others and move only wwin */
1687 wUnselectWindows(scr);
1689 #ifdef DEBUG
1690 puts("Moving window");
1691 #endif
1692 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1693 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1694 while (!done) {
1695 if (warped) {
1696 int junk;
1697 Window junkw;
1699 /* XWarpPointer() doesn't seem to generate Motion events, so
1700 * we've got to simulate them */
1701 XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
1702 &event.xmotion.y_root, &junk, &junk,
1703 (unsigned *) &junk);
1704 } else {
1705 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
1706 | PointerMotionHintMask
1707 | ButtonReleaseMask | ButtonPressMask | ExposureMask,
1708 &event);
1710 if (event.type == MotionNotify) {
1711 /* compress MotionNotify events */
1712 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
1713 if (!checkMouseSamplingRate(&event))
1714 continue;
1717 switch (event.type) {
1718 case KeyPress:
1719 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1720 && started && !scr->selected_windows) {
1722 if (!opaqueMove) {
1723 drawFrames(wwin, scr->selected_windows,
1724 moveData.realX - wwin->frame_x,
1725 moveData.realY - wwin->frame_y);
1728 if (wPreferences.move_display == WDIS_NEW
1729 && !scr->selected_windows) {
1730 showPosition(wwin, moveData.realX, moveData.realY);
1731 XUngrabServer(dpy);
1733 cyclePositionDisplay(wwin, moveData.realX, moveData.realY,
1734 moveData.winWidth, moveData.winHeight);
1736 if (wPreferences.move_display == WDIS_NEW
1737 && !scr->selected_windows) {
1738 XGrabServer(dpy);
1739 showPosition(wwin, moveData.realX, moveData.realY);
1742 if (!opaqueMove) {
1743 drawFrames(wwin, scr->selected_windows,
1744 moveData.realX - wwin->frame_x,
1745 moveData.realY - wwin->frame_y);
1747 /*} else {
1748 WMHandleEvent(&event); this causes problems needs fixing */
1750 break;
1752 case MotionNotify:
1753 if (started) {
1754 updateWindowPosition(wwin, &moveData,
1755 scr->selected_windows == NULL
1756 && wPreferences.edge_resistance > 0,
1757 opaqueMove,
1758 event.xmotion.x_root,
1759 event.xmotion.y_root);
1761 if (!warped && !wPreferences.no_autowrap) {
1762 int oldWorkspace = scr->current_workspace;
1764 if (wPreferences.move_display == WDIS_NEW
1765 && !scr->selected_windows) {
1766 showPosition(wwin, moveData.realX, moveData.realY);
1767 XUngrabServer(dpy);
1769 if (!opaqueMove) {
1770 drawFrames(wwin, scr->selected_windows,
1771 moveData.realX - wwin->frame_x,
1772 moveData.realY - wwin->frame_y);
1774 if (checkWorkspaceChange(wwin, &moveData, opaqueMove)) {
1775 if (scr->current_workspace != oldWorkspace
1776 && wPreferences.edge_resistance > 0
1777 && scr->selected_windows == NULL)
1778 updateMoveData(wwin, &moveData);
1779 warped = 1;
1781 if (!opaqueMove) {
1782 drawFrames(wwin, scr->selected_windows,
1783 moveData.realX - wwin->frame_x,
1784 moveData.realY - wwin->frame_y);
1786 if (wPreferences.move_display == WDIS_NEW
1787 && !scr->selected_windows) {
1788 XSync(dpy, False);
1789 showPosition(wwin, moveData.realX, moveData.realY);
1790 XGrabServer(dpy);
1792 } else {
1793 warped = 0;
1795 } else if (abs(ev->xmotion.x_root - event.xmotion.x_root) >= MOVE_THRESHOLD
1796 || abs(ev->xmotion.y_root - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1798 XChangeActivePointerGrab(dpy, ButtonMotionMask
1799 | ButtonReleaseMask | ButtonPressMask,
1800 wCursor[WCUR_MOVE], CurrentTime);
1801 started = 1;
1802 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
1803 CurrentTime);
1805 if (!scr->selected_windows)
1806 mapPositionDisplay(wwin, moveData.realX, moveData.realY,
1807 moveData.winWidth, moveData.winHeight);
1809 if (started && !opaqueMove)
1810 drawFrames(wwin, scr->selected_windows, 0, 0);
1812 if (!opaqueMove || (wPreferences.move_display==WDIS_NEW
1813 && !scr->selected_windows)) {
1814 XGrabServer(dpy);
1815 if (wPreferences.move_display==WDIS_NEW)
1816 showPosition(wwin, moveData.realX, moveData.realY);
1819 break;
1821 case ButtonPress:
1822 break;
1824 case ButtonRelease:
1825 if (event.xbutton.button != ev->xbutton.button)
1826 break;
1828 if (started) {
1829 XEvent e;
1830 if (!opaqueMove) {
1831 drawFrames(wwin, scr->selected_windows,
1832 moveData.realX - wwin->frame_x,
1833 moveData.realY - wwin->frame_y);
1834 XSync(dpy, 0);
1835 doWindowMove(wwin, scr->selected_windows,
1836 moveData.realX - wwin->frame_x,
1837 moveData.realY - wwin->frame_y);
1839 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
1840 wWindowSynthConfigureNotify(wwin);
1841 #endif
1842 XUngrabKeyboard(dpy, CurrentTime);
1843 XUngrabServer(dpy);
1844 if (!opaqueMove) {
1845 wWindowChangeWorkspace(wwin, scr->current_workspace);
1846 wSetFocusTo(scr, wwin);
1848 if (wPreferences.move_display == WDIS_NEW)
1849 showPosition(wwin, moveData.realX, moveData.realY);
1851 /* discard all enter/leave events that happened until
1852 * the time the button was released */
1853 while (XCheckTypedEvent(dpy, EnterNotify, &e)) {
1854 if (e.xcrossing.time > event.xbutton.time) {
1855 XPutBackEvent(dpy, &e);
1856 break;
1859 while (XCheckTypedEvent(dpy, LeaveNotify, &e)) {
1860 if (e.xcrossing.time > event.xbutton.time) {
1861 XPutBackEvent(dpy, &e);
1862 break;
1866 if (!scr->selected_windows) {
1867 /* get rid of the geometry window */
1868 WMUnmapWidget(scr->gview);
1871 #ifdef DEBUG
1872 puts("End move window");
1873 #endif
1874 done = True;
1875 break;
1877 default:
1878 if (started && !opaqueMove) {
1879 drawFrames(wwin, scr->selected_windows,
1880 moveData.realX - wwin->frame_x,
1881 moveData.realY - wwin->frame_y);
1882 XUngrabServer(dpy);
1883 WMHandleEvent(&event);
1884 XSync(dpy, False);
1885 XGrabServer(dpy);
1886 drawFrames(wwin, scr->selected_windows,
1887 moveData.realX - wwin->frame_x,
1888 moveData.realY - wwin->frame_y);
1889 } else {
1890 WMHandleEvent(&event);
1892 break;
1896 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1897 XSetWindowAttributes attr;
1900 attr.save_under = False;
1901 XChangeWindowAttributes(dpy, wwin->frame->core->window,
1902 CWSaveUnder, &attr);
1906 freeMoveData(&moveData);
1908 return started;
1912 #define RESIZEBAR 1
1913 #define HCONSTRAIN 2
1915 static int
1916 getResizeDirection(WWindow *wwin, int x, int y, int dx, int dy,
1917 int flags)
1919 int w = wwin->frame->core->width - 1;
1920 int cw = wwin->frame->resizebar_corner_width;
1921 int dir;
1923 /* if not resizing through the resizebar */
1924 if (!(flags & RESIZEBAR)) {
1925 int xdir = (abs(x) < (wwin->client.width/2)) ? LEFT : RIGHT;
1926 int ydir = (abs(y) < (wwin->client.height/2)) ? UP : DOWN;
1927 if (abs(dx) < 2 || abs(dy) < 2) {
1928 if (abs(dy) > abs(dx))
1929 xdir = 0;
1930 else
1931 ydir = 0;
1933 return (xdir | ydir);
1936 /* window is too narrow. allow diagonal resize */
1937 if (cw * 2 >= w) {
1938 int ydir;
1940 if (flags & HCONSTRAIN)
1941 ydir = 0;
1942 else
1943 ydir = DOWN;
1944 if (x < cw)
1945 return (LEFT | ydir);
1946 else
1947 return (RIGHT | ydir);
1949 /* vertical resize */
1950 if ((x > cw) && (x < w - cw))
1951 return DOWN;
1953 if (x < cw)
1954 dir = LEFT;
1955 else
1956 dir = RIGHT;
1958 if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
1959 dir |= DOWN;
1961 return dir;
1965 void
1966 wMouseResizeWindow(WWindow *wwin, XEvent *ev)
1968 XEvent event;
1969 WScreen *scr = wwin->screen_ptr;
1970 Window root = scr->root_win;
1971 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1972 int fw = wwin->frame->core->width;
1973 int fh = wwin->frame->core->height;
1974 int fx = wwin->frame_x;
1975 int fy = wwin->frame_y;
1976 int is_resizebar = (wwin->frame->resizebar
1977 && ev->xany.window==wwin->frame->resizebar->window);
1978 int orig_x, orig_y;
1979 int started;
1980 int dw, dh;
1981 int rw = fw, rh = fh;
1982 int rx1, ry1, rx2, ry2;
1983 int res = 0;
1984 KeyCode shiftl, shiftr;
1985 int h = 0;
1986 int orig_fx = fx;
1987 int orig_fy = fy;
1988 int orig_fw = fw;
1989 int orig_fh = fh;
1991 if (wwin->flags.shaded) {
1992 wwarning("internal error: tryein");
1993 return;
1995 orig_x = ev->xbutton.x_root;
1996 orig_y = ev->xbutton.y_root;
1998 started = 0;
1999 #ifdef DEBUG
2000 puts("Resizing window");
2001 #endif
2003 wUnselectWindows(scr);
2004 rx1 = fx;
2005 rx2 = fx + fw - 1;
2006 ry1 = fy;
2007 ry2 = fy + fh - 1;
2008 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
2009 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
2010 if (!WFLAGP(wwin, no_titlebar))
2011 h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
2012 else
2013 h = 0;
2014 while (1) {
2015 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
2016 | ButtonReleaseMask | PointerMotionHintMask
2017 | ButtonPressMask | ExposureMask, &event);
2018 if (!checkMouseSamplingRate(&event))
2019 continue;
2021 switch (event.type) {
2022 case KeyPress:
2023 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2024 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
2025 && started) {
2026 drawTransparentFrame(wwin, fx, fy, fw, fh);
2027 cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
2028 drawTransparentFrame(wwin, fx, fy, fw, fh);
2030 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2031 break;
2033 case MotionNotify:
2034 if (started) {
2035 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
2037 dw = 0;
2038 dh = 0;
2040 orig_fx = fx;
2041 orig_fy = fy;
2042 orig_fw = fw;
2043 orig_fh = fh;
2045 if (res & LEFT)
2046 dw = orig_x - event.xmotion.x_root;
2047 else if (res & RIGHT)
2048 dw = event.xmotion.x_root - orig_x;
2049 if (res & UP)
2050 dh = orig_y - event.xmotion.y_root;
2051 else if (res & DOWN)
2052 dh = event.xmotion.y_root - orig_y;
2054 orig_x = event.xmotion.x_root;
2055 orig_y = event.xmotion.y_root;
2057 rw += dw;
2058 rh += dh;
2059 fw = rw;
2060 fh = rh - vert_border;
2061 wWindowConstrainSize(wwin, &fw, &fh);
2062 fh += vert_border;
2063 if (res & LEFT)
2064 fx = rx2 - fw + 1;
2065 else if (res & RIGHT)
2066 fx = rx1;
2067 if (res & UP)
2068 fy = ry2 - fh + 1;
2069 else if (res & DOWN)
2070 fy = ry1;
2071 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
2072 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
2073 int tx, ty;
2074 Window junkw;
2075 int flags;
2077 XTranslateCoordinates(dpy, root, wwin->frame->core->window,
2078 orig_x, orig_y, &tx, &ty, &junkw);
2080 /* check if resizing through resizebar */
2081 if (is_resizebar)
2082 flags = RESIZEBAR;
2083 else
2084 flags = 0;
2086 if (is_resizebar && ((ev->xbutton.state & ShiftMask)
2087 || abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
2088 flags |= HCONSTRAIN;
2090 res = getResizeDirection(wwin, tx, ty,
2091 orig_x - event.xmotion.x_root,
2092 orig_y - event.xmotion.y_root, flags);
2094 if (res == (UP|LEFT))
2095 XChangeActivePointerGrab(dpy, ButtonMotionMask
2096 | ButtonReleaseMask | ButtonPressMask,
2097 wCursor[WCUR_TOPLEFTRESIZE], CurrentTime);
2098 else if (res == (UP|RIGHT))
2099 XChangeActivePointerGrab(dpy, ButtonMotionMask
2100 | ButtonReleaseMask | ButtonPressMask,
2101 wCursor[WCUR_TOPRIGHTRESIZE], CurrentTime);
2102 else if (res == (DOWN|LEFT))
2103 XChangeActivePointerGrab(dpy, ButtonMotionMask
2104 | ButtonReleaseMask | ButtonPressMask,
2105 wCursor[WCUR_BOTTOMLEFTRESIZE], CurrentTime);
2106 else if (res == (DOWN|RIGHT))
2107 XChangeActivePointerGrab(dpy, ButtonMotionMask
2108 | ButtonReleaseMask | ButtonPressMask,
2109 wCursor[WCUR_BOTTOMRIGHTRESIZE], CurrentTime);
2110 else if (res == DOWN || res == UP)
2111 XChangeActivePointerGrab(dpy, ButtonMotionMask
2112 | ButtonReleaseMask | ButtonPressMask,
2113 wCursor[WCUR_VERTICALRESIZE], CurrentTime);
2114 else if (res & (DOWN|UP))
2115 XChangeActivePointerGrab(dpy, ButtonMotionMask
2116 | ButtonReleaseMask | ButtonPressMask,
2117 wCursor[WCUR_VERTICALRESIZE], CurrentTime);
2118 else if (res & (LEFT|RIGHT))
2119 XChangeActivePointerGrab(dpy, ButtonMotionMask
2120 | ButtonReleaseMask | ButtonPressMask,
2121 wCursor[WCUR_HORIZONRESIZE], CurrentTime);
2123 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
2124 CurrentTime);
2126 XGrabServer(dpy);
2128 /* Draw the resize frame for the first time. */
2129 mapGeometryDisplay(wwin, fx, fy, fw, fh);
2131 drawTransparentFrame(wwin, fx, fy, fw, fh);
2133 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2135 started = 1;
2137 if (started) {
2138 if (wPreferences.size_display == WDIS_FRAME_CENTER) {
2139 drawTransparentFrame(wwin, orig_fx, orig_fy,
2140 orig_fw, orig_fh);
2141 moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
2142 drawTransparentFrame(wwin, fx, fy, fw, fh);
2143 } else {
2144 drawTransparentFrame(wwin, orig_fx, orig_fy,
2145 orig_fw, orig_fh);
2146 drawTransparentFrame(wwin, fx, fy, fw, fh);
2148 if (fh != orig_fh || fw != orig_fw) {
2149 if (wPreferences.size_display == WDIS_NEW) {
2150 showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw,
2151 orig_fy + orig_fh, res);
2153 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2156 break;
2158 case ButtonPress:
2159 break;
2161 case ButtonRelease:
2162 if (event.xbutton.button != ev->xbutton.button)
2163 break;
2165 if (started) {
2166 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2168 drawTransparentFrame(wwin, fx, fy, fw, fh);
2170 XUngrabKeyboard(dpy, CurrentTime);
2171 WMUnmapWidget(scr->gview);
2172 XUngrabServer(dpy);
2174 if (wwin->client.width != fw)
2175 wwin->flags.user_changed_width = 1;
2177 if (wwin->client.height != fh - vert_border)
2178 wwin->flags.user_changed_height = 1;
2180 wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
2182 #ifdef DEBUG
2183 puts("End resize window");
2184 #endif
2185 return;
2187 default:
2188 WMHandleEvent(&event);
2193 #undef LEFT
2194 #undef RIGHT
2195 #undef HORIZONTAL
2196 #undef UP
2197 #undef DOWN
2198 #undef VERTICAL
2199 #undef HCONSTRAIN
2200 #undef RESIZEBAR
2202 void
2203 wUnselectWindows(WScreen *scr)
2205 WWindow *wwin;
2207 if (!scr->selected_windows)
2208 return;
2210 while (WMGetArrayItemCount(scr->selected_windows)) {
2211 wwin = WMGetFromArray(scr->selected_windows, 0);
2212 if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
2213 wIconSelect(wwin->icon);
2215 wSelectWindow(wwin, False);
2217 WMFreeArray(scr->selected_windows);
2218 scr->selected_windows = NULL;
2221 #ifndef LITE
2222 static void
2223 selectWindowsInside(WScreen *scr, int x1, int y1, int x2, int y2)
2225 WWindow *tmpw;
2227 /* select the windows and put them in the selected window list */
2228 tmpw = scr->focused_window;
2229 while (tmpw != NULL) {
2230 if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
2231 if ((tmpw->frame->workspace == scr->current_workspace
2232 || IS_OMNIPRESENT(tmpw))
2233 && (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1)
2234 && (tmpw->frame->core->width + tmpw->frame_x <= x2)
2235 && (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
2236 wSelectWindow(tmpw, True);
2239 tmpw = tmpw->prev;
2244 void
2245 wSelectWindows(WScreen *scr, XEvent *ev)
2247 XEvent event;
2248 Window root = scr->root_win;
2249 GC gc = scr->frame_gc;
2250 int xp = ev->xbutton.x_root;
2251 int yp = ev->xbutton.y_root;
2252 int w = 0, h = 0;
2253 int x = xp, y = yp;
2255 #ifdef DEBUG
2256 puts("Selecting windows");
2257 #endif
2258 if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
2259 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
2260 GrabModeAsync, None, wCursor[WCUR_DEFAULT],
2261 CurrentTime) != Success) {
2262 return;
2264 XGrabServer(dpy);
2266 wUnselectWindows(scr);
2268 XDrawRectangle(dpy, root, gc, xp, yp, w, h);
2269 while (1) {
2270 WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask
2271 | ButtonPressMask, &event);
2273 switch (event.type) {
2274 case MotionNotify:
2275 XDrawRectangle(dpy, root, gc, x, y, w, h);
2276 x = event.xmotion.x_root;
2277 if (x < xp) {
2278 w = xp - x;
2279 } else {
2280 w = x - xp;
2281 x = xp;
2283 y = event.xmotion.y_root;
2284 if (y < yp) {
2285 h = yp - y;
2286 } else {
2287 h = y - yp;
2288 y = yp;
2290 XDrawRectangle(dpy, root, gc, x, y, w, h);
2291 break;
2293 case ButtonPress:
2294 break;
2296 case ButtonRelease:
2297 if (event.xbutton.button != ev->xbutton.button)
2298 break;
2300 XDrawRectangle(dpy, root, gc, x, y, w, h);
2301 XUngrabServer(dpy);
2302 XUngrabPointer(dpy, CurrentTime);
2303 selectWindowsInside(scr, x, y, x + w, y + h);
2305 #ifdef KWM_HINTS
2306 wKWMSelectRootRegion(scr, xp, yp, w, h,
2307 event.xbutton.state & ControlMask);
2308 #endif /* KWM_HINTS */
2310 #ifdef DEBUG
2311 puts("End window selection");
2312 #endif
2313 return;
2315 default:
2316 WMHandleEvent(&event);
2317 break;
2321 #endif /* !LITE */
2323 void
2324 InteractivePlaceWindow(WWindow *wwin, int *x_ret, int *y_ret,
2325 unsigned width, unsigned height)
2327 WScreen *scr = wwin->screen_ptr;
2328 Window root = scr->root_win;
2329 int x, y, h = 0;
2330 XEvent event;
2331 KeyCode shiftl, shiftr;
2332 Window junkw;
2333 int junk;
2335 if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
2336 GrabModeAsync, GrabModeAsync, None,
2337 wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
2338 *x_ret = 0;
2339 *y_ret = 0;
2340 return;
2342 if (!WFLAGP(wwin, no_titlebar)) {
2343 h = WMFontHeight(scr->title_font) + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
2344 height += h;
2346 if (!WFLAGP(wwin, no_resizebar)) {
2347 height += RESIZEBAR_HEIGHT;
2349 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
2350 XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk,
2351 (unsigned *) &junk);
2352 mapPositionDisplay(wwin, x - width/2, y - h/2, width, height);
2354 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2356 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
2357 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
2358 while (1) {
2359 WMMaskEvent(dpy, PointerMotionMask|ButtonPressMask|ExposureMask|KeyPressMask,
2360 &event);
2362 if (!checkMouseSamplingRate(&event))
2363 continue;
2365 switch (event.type) {
2366 case KeyPress:
2367 if ((event.xkey.keycode == shiftl)
2368 || (event.xkey.keycode == shiftr)) {
2369 drawTransparentFrame(wwin,
2370 x - width/2, y - h/2, width, height);
2371 cyclePositionDisplay(wwin,
2372 x - width/2, y - h/2, width, height);
2373 drawTransparentFrame(wwin,
2374 x - width/2, y - h/2, width, height);
2376 break;
2378 case MotionNotify:
2379 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2381 x = event.xmotion.x_root;
2382 y = event.xmotion.y_root;
2384 if (wPreferences.move_display == WDIS_FRAME_CENTER)
2385 moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
2387 showPosition(wwin, x - width/2, y - h/2);
2389 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2391 break;
2393 case ButtonPress:
2394 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2395 XSync(dpy, 0);
2396 *x_ret = x - width/2;
2397 *y_ret = y - h/2;
2398 XUngrabPointer(dpy, CurrentTime);
2399 XUngrabKeyboard(dpy, CurrentTime);
2400 /* get rid of the geometry window */
2401 WMUnmapWidget(scr->gview);
2402 return;
2404 default:
2405 WMHandleEvent(&event);
2406 break;