- Fixed userdefaults in WINGs not to synchronize on exit a domain that is
[wmaker-crm.git] / src / moveres.c
blobb8238ae6bc1b53a22a48fa00cca60e0ee12191a1
1 /*
2 * Window Maker window manager
4 * Copyright (c) 1997-2002 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"
45 #include <WINGs/WINGsP.h>
48 #ifdef KWM_HINTS
49 #include "kwm.h"
50 #endif
52 /* How many different types of geometry/position
53 display thingies are there? */
54 #define NUM_DISPLAYS 5
56 #define LEFT 1
57 #define RIGHT 2
58 #define HORIZONTAL (LEFT|RIGHT)
59 #define UP 4
60 #define DOWN 8
61 #define VERTICAL (UP|DOWN)
63 /****** Global Variables ******/
64 extern Time LastTimestamp;
66 extern Cursor wCursor[WCUR_LAST];
68 extern WPreferences wPreferences;
70 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
83 checkMouseSamplingRate(XEvent *ev)
85 static Time previousMotion = 0;
87 if (ev->type == MotionNotify) {
88 if (ev->xmotion.time - previousMotion < DELAY_BETWEEN_MOUSE_SAMPLING) {
89 return False;
90 } else {
91 previousMotion = ev->xmotion.time;
94 return True;
100 *----------------------------------------------------------------------
101 * moveGeometryDisplayCentered
103 * routine that moves the geometry/position window on scr so it is
104 * centered over the given coordinates (x,y). Also the window position
105 * is clamped so it stays on the screen at all times.
106 *----------------------------------------------------------------------
108 static void
109 moveGeometryDisplayCentered(WScreen *scr, int x, int y)
111 unsigned int w = WMWidgetWidth(scr->gview);
112 unsigned int h = WMWidgetHeight(scr->gview);
114 x -= w / 2;
115 y -= h / 2;
117 if (x < 1)
118 x = 1;
119 else if (x > (scr->scr_width - w - 3))
120 x = scr->scr_width - w - 3;
122 if (y < 1)
123 y = 1;
124 else if (y > (scr->scr_height - h - 3))
125 y = scr->scr_height - h - 3;
127 WMMoveWidget(scr->gview, x, y);
131 static void
132 showPosition(WWindow *wwin, int x, int y)
134 WScreen *scr = wwin->screen_ptr;
136 if (wPreferences.move_display == WDIS_NEW) {
137 #if 0
138 int width = wwin->frame->core->width;
139 int height = wwin->frame->core->height;
141 GC lgc = scr->line_gc;
142 XSetForeground(dpy, lgc, scr->line_pixel);
143 sprintf(num, "%i", x);
145 XDrawLine(dpy, scr->root_win, lgc, 0, y-1, scr->scr_width, y-1);
146 XDrawLine(dpy, scr->root_win, lgc, 0, y+height+2, scr->scr_width,
147 y+height+2);
148 XDrawLine(dpy, scr->root_win, lgc, x-1, 0, x-1, scr->scr_height);
149 XDrawLine(dpy, scr->root_win, lgc, x+width+2, 0, x+width+2,
150 scr->scr_height);
151 #endif
152 } else {
153 #ifdef VIRTUAL_DESKTOP
154 WSetGeometryViewShownPosition(scr->gview,
155 x + scr->workspaces[scr->current_workspace]->view_x,
156 y + scr->workspaces[scr->current_workspace]->view_y);
157 #else
158 WSetGeometryViewShownPosition(scr->gview, x, y);
159 #endif
164 static void
165 cyclePositionDisplay(WWindow *wwin, int x, int y, int w, int h)
167 WScreen *scr = wwin->screen_ptr;
169 wPreferences.move_display++;
170 wPreferences.move_display %= NUM_DISPLAYS;
172 if (wPreferences.move_display == WDIS_NEW) {
173 wPreferences.move_display++;
174 wPreferences.move_display %= NUM_DISPLAYS;
177 if (wPreferences.move_display == WDIS_NONE) {
178 WMUnmapWidget(scr->gview);
179 } else {
180 if (wPreferences.move_display == WDIS_CENTER) {
181 moveGeometryDisplayCentered(scr,
182 scr->scr_width/2, scr->scr_height/2);
183 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
184 moveGeometryDisplayCentered(scr, 1, 1);
185 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
186 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
188 WMMapWidget(scr->gview);
193 static void
194 mapPositionDisplay(WWindow *wwin, int x, int y, int w, int h)
196 WScreen *scr = wwin->screen_ptr;
198 if (wPreferences.move_display == WDIS_NEW
199 || wPreferences.move_display == WDIS_NONE) {
200 return;
201 } else if (wPreferences.move_display == WDIS_CENTER) {
202 moveGeometryDisplayCentered(scr, scr->scr_width / 2,
203 scr->scr_height / 2);
204 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
205 moveGeometryDisplayCentered(scr, 1, 1);
206 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
207 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
209 WMMapWidget(scr->gview);
210 WSetGeometryViewShownPosition(scr->gview, x, y);
214 static void
215 showGeometry(WWindow *wwin, int x1, int y1, int x2, int y2, int direction)
217 WScreen *scr = wwin->screen_ptr;
218 Window root = scr->root_win;
219 GC gc = scr->line_gc, saveGC;
220 int ty, by, my, x, y, mx, s;
221 char num[16];
222 XSegment segment[4];
223 int fw, fh;
224 WMColor *color;
225 WMPixel pixel;
227 ty = y1 + wwin->frame->top_width;
228 by = y2 - wwin->frame->bottom_width;
230 if (wPreferences.size_display == WDIS_NEW) {
231 fw = WMWidthOfString(scr->tech_draw_font, "8888", 4);
232 fh = WMFontHeight(scr->tech_draw_font);
234 XSetForeground(dpy, gc, scr->line_pixel);
236 /* vertical geometry */
237 if (((direction & LEFT) && (x2 < scr->scr_width - fw)) || (x1 < fw)) {
238 x = x2;
239 s = -15;
240 } else {
241 x = x1;
242 s = 15;
244 my = (ty + by) / 2;
246 /* top arrow */
247 /* end bar */
248 segment[0].x1 = x - (s + 6); segment[0].y1 = ty;
249 segment[0].x2 = x - (s - 10); segment[0].y2 = ty;
251 /* arrowhead */
252 segment[1].x1 = x - (s - 2); segment[1].y1 = ty + 1;
253 segment[1].x2 = x - (s - 5); segment[1].y2 = ty + 7;
255 segment[2].x1 = x - (s - 2); segment[2].y1 = ty + 1;
256 segment[2].x2 = x - (s + 1); segment[2].y2 = ty + 7;
258 /* line */
259 segment[3].x1 = x - (s - 2); segment[3].y1 = ty + 1;
260 segment[3].x2 = x - (s - 2); segment[3].y2 = my - fh/2 - 1;
262 XDrawSegments(dpy, root, gc, segment, 4);
264 /* bottom arrow */
265 /* end bar */
266 segment[0].y1 = by;
267 segment[0].y2 = by;
269 /* arrowhead */
270 segment[1].y1 = by - 1;
271 segment[1].y2 = by - 7;
273 segment[2].y1 = by - 1;
274 segment[2].y2 = by - 7;
276 /* line */
277 segment[3].y1 = my + fh/2 + 2;
278 segment[3].y2 = by - 1;
280 XDrawSegments(dpy, root, gc, segment, 4);
282 snprintf(num, sizeof(num), "%i", (by - ty - wwin->normal_hints->base_height) /
283 wwin->normal_hints->height_inc);
284 fw = WMWidthOfString(scr->tech_draw_font, num, strlen(num));
286 /* XSetForeground(dpy, gc, WMColorPixel(scr->window_title_color[WS_UNFOCUSED])); */
288 color = WMBlackColor(scr->wmscreen);
289 saveGC = scr->wmscreen->drawStringGC;
290 pixel = color->color.pixel;
292 /* Display the height. */
294 /* // ugly hack */
295 color->color.pixel = scr->line_pixel;
296 scr->wmscreen->drawStringGC = gc;
297 WMDrawString(scr->wmscreen, root, color, scr->tech_draw_font,
298 x - s + 3 - fw/2, my - fh/2 + 1, num, strlen(num));
299 scr->wmscreen->drawStringGC = saveGC;
300 color->color.pixel = pixel;
302 XSetForeground(dpy, gc, scr->line_pixel);
303 /* horizontal geometry */
304 if (y1 < 15) {
305 y = y2;
306 s = -15;
307 } else {
308 y = y1;
309 s = 15;
311 mx = x1 + (x2 - x1)/2;
312 snprintf(num, sizeof(num), "%i", (x2 - x1 - wwin->normal_hints->base_width) /
313 wwin->normal_hints->width_inc);
314 fw = WMWidthOfString(scr->tech_draw_font, num, strlen(num));
316 /* left arrow */
317 /* end bar */
318 segment[0].x1 = x1; segment[0].y1 = y - (s + 6);
319 segment[0].x2 = x1; segment[0].y2 = y - (s - 10);
321 /* arrowhead */
322 segment[1].x1 = x1 + 7; segment[1].y1 = y - (s + 1);
323 segment[1].x2 = x1 + 1; segment[1].y2 = y - (s - 2);
325 segment[2].x1 = x1 + 1; segment[2].y1 = y - (s - 2);
326 segment[2].x2 = x1 + 7; segment[2].y2 = y - (s - 5);
328 /* line */
329 segment[3].x1 = x1 + 1; segment[3].y1 = y - (s - 2);
330 segment[3].x2 = mx - fw/2 - 2; segment[3].y2 = y - (s - 2);
332 XDrawSegments(dpy, root, gc, segment, 4);
334 /* right arrow */
335 /* end bar */
336 segment[0].x1 = x2 + 1;
337 segment[0].x2 = x2 + 1;
339 /* arrowhead */
340 segment[1].x1 = x2 - 6;
341 segment[1].x2 = x2;
343 segment[2].x1 = x2;
344 segment[2].x2 = x2 - 6;
346 /* line */
347 segment[3].x1 = mx + fw/2 + 2;
348 segment[3].x2 = x2;
350 XDrawSegments(dpy, root, gc, segment, 4);
352 /* XSetForeground(dpy, gc, WMColorPixel(scr->window_title_color[WS_UNFOCUSED])); */
354 /* Display the width. */
355 /* // ugly hack */
356 color->color.pixel = scr->line_pixel;
357 scr->wmscreen->drawStringGC = gc;
358 WMDrawString(scr->wmscreen, root, color, scr->tech_draw_font,
359 mx - fw/2 + 1, y - s - fh/2 + 1, num, strlen(num));
360 scr->wmscreen->drawStringGC = saveGC;
361 color->color.pixel = pixel;
362 WMReleaseColor(color);
363 } else {
364 WSetGeometryViewShownSize(scr->gview,
365 (x2 - x1 - wwin->normal_hints->base_width)
366 / wwin->normal_hints->width_inc,
367 (by - ty - wwin->normal_hints->base_height)
368 / wwin->normal_hints->height_inc);
373 static void
374 cycleGeometryDisplay(WWindow *wwin, int x, int y, int w, int h, int dir)
376 WScreen *scr = wwin->screen_ptr;
378 wPreferences.size_display++;
379 wPreferences.size_display %= NUM_DISPLAYS;
381 if (wPreferences.size_display == WDIS_NEW
382 || wPreferences.size_display == WDIS_NONE) {
383 WMUnmapWidget(scr->gview);
384 } else {
385 if (wPreferences.size_display == WDIS_CENTER) {
386 moveGeometryDisplayCentered(scr,
387 scr->scr_width / 2, scr->scr_height / 2);
388 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
389 moveGeometryDisplayCentered(scr, 1, 1);
390 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
391 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
393 WMMapWidget(scr->gview);
394 showGeometry(wwin, x, y, x + w, y + h, dir);
399 static void
400 mapGeometryDisplay(WWindow *wwin, int x, int y, int w, int h)
402 WScreen *scr = wwin->screen_ptr;
404 if (wPreferences.size_display == WDIS_NEW
405 || wPreferences.size_display == WDIS_NONE)
406 return;
408 if (wPreferences.size_display == WDIS_CENTER) {
409 moveGeometryDisplayCentered(scr, scr->scr_width / 2,
410 scr->scr_height / 2);
411 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
412 moveGeometryDisplayCentered(scr, 1, 1);
413 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
414 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
416 WMMapWidget(scr->gview);
417 showGeometry(wwin, x, y, x + w, y + h, 0);
422 static void
423 doWindowMove(WWindow *wwin, WMArray *array, int dx, int dy)
425 WWindow *tmpw;
426 int x, y;
427 int scr_width = wwin->screen_ptr->scr_width;
428 int scr_height = wwin->screen_ptr->scr_height;
430 if (!array || !WMGetArrayItemCount(array)) {
431 wWindowMove(wwin, wwin->frame_x + dx, wwin->frame_y + dy);
432 } else {
433 WMArrayIterator iter;
435 WM_ITERATE_ARRAY(array, tmpw, iter) {
436 x = tmpw->frame_x + dx;
437 y = tmpw->frame_y + dy;
439 /* don't let windows become unreachable */
441 if (x + (int)tmpw->frame->core->width < 20)
442 x = 20 - (int)tmpw->frame->core->width;
443 else if (x + 20 > scr_width)
444 x = scr_width - 20;
446 if (y + (int)tmpw->frame->core->height < 20)
447 y = 20 - (int)tmpw->frame->core->height;
448 else if (y + 20 > scr_height)
449 y = scr_height - 20;
451 wWindowMove(tmpw, x, y);
457 static void
458 drawTransparentFrame(WWindow *wwin, int x, int y, int width, int height)
460 Window root = wwin->screen_ptr->root_win;
461 GC gc = wwin->screen_ptr->frame_gc;
462 int h = 0;
463 int bottom = 0;
465 if (!WFLAGP(wwin, no_titlebar) && !wwin->flags.shaded) {
466 h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
468 if (!WFLAGP(wwin, no_resizebar) && !wwin->flags.shaded) {
469 /* Can't use wwin-frame->bottom_width because, in some cases
470 (e.g. interactive placement), frame does not point to anything. */
471 bottom = RESIZEBAR_HEIGHT - 1;
473 XDrawRectangle(dpy, root, gc, x, y, width + 1, height + 1);
475 if (h > 0) {
476 XDrawLine(dpy, root, gc, x + 1, y + h, x + width + 1, y + h);
478 if (bottom > 0) {
479 XDrawLine(dpy, root, gc, x + 1,
480 y + height - bottom,
481 x + width + 1,
482 y + height - bottom);
487 static void
488 drawFrames(WWindow *wwin, WMArray *array, int dx, int dy)
490 WWindow *tmpw;
491 int scr_width = wwin->screen_ptr->scr_width;
492 int scr_height = wwin->screen_ptr->scr_height;
493 int x, y;
495 if (!array) {
497 x = wwin->frame_x + dx;
498 y = wwin->frame_y + dy;
500 drawTransparentFrame(wwin, x, y,
501 wwin->frame->core->width,
502 wwin->frame->core->height);
504 } else {
505 WMArrayIterator iter;
507 WM_ITERATE_ARRAY(array, tmpw, iter) {
508 x = tmpw->frame_x + dx;
509 y = tmpw->frame_y + dy;
511 /* don't let windows become unreachable */
513 if (x + (int)tmpw->frame->core->width < 20)
514 x = 20 - (int)tmpw->frame->core->width;
515 else if (x + 20 > scr_width)
516 x = scr_width - 20;
518 if (y + (int)tmpw->frame->core->height < 20)
519 y = 20 - (int)tmpw->frame->core->height;
520 else if (y + 20 > scr_height)
521 y = scr_height - 20;
523 drawTransparentFrame(tmpw, x, y, tmpw->frame->core->width,
524 tmpw->frame->core->height);
531 static void
532 flushMotion()
534 XEvent ev;
536 XSync(dpy, False);
537 while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
541 static void
542 crossWorkspace(WScreen *scr, WWindow *wwin, int opaque_move,
543 int new_workspace, int rewind)
545 /* do not let window be unmapped */
546 if (opaque_move) {
547 wwin->flags.changing_workspace = 1;
548 wWindowChangeWorkspace(wwin, new_workspace);
550 /* go to new workspace */
551 wWorkspaceChange(scr, new_workspace);
553 wwin->flags.changing_workspace = 0;
555 if (rewind)
556 XWarpPointer(dpy, None, None, 0, 0, 0, 0, scr->scr_width - 20, 0);
557 else
558 XWarpPointer(dpy, None, None, 0, 0, 0, 0, -(scr->scr_width - 20), 0);
560 flushMotion();
562 if (!opaque_move) {
563 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
564 |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
565 GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
572 typedef struct {
573 /* arrays of WWindows sorted by the respective border position */
574 WWindow **topList; /* top border */
575 WWindow **leftList; /* left border */
576 WWindow **rightList; /* right border */
577 WWindow **bottomList; /* bottom border */
578 int count;
580 /* index of window in the above lists indicating the relative position
581 * of the window with the others */
582 int topIndex;
583 int leftIndex;
584 int rightIndex;
585 int bottomIndex;
587 int rubCount; /* for workspace switching */
589 int winWidth, winHeight; /* width/height of the window */
590 int realX, realY; /* actual position of the window */
591 int calcX, calcY; /* calculated position of window */
592 int omouseX, omouseY; /* old mouse position */
593 int mouseX, mouseY; /* last known position of the pointer */
594 } MoveData;
596 #define WTOP(w) (w)->frame_y
597 #define WLEFT(w) (w)->frame_x
598 #define WRIGHT(w) ((w)->frame_x + (int)(w)->frame->core->width + FRAME_BORDER_WIDTH)
599 #define WBOTTOM(w) ((w)->frame_y + (int)(w)->frame->core->height + FRAME_BORDER_WIDTH)
601 static int
602 compareWTop(const void *a, const void *b)
604 WWindow *wwin1 = *(WWindow**)a;
605 WWindow *wwin2 = *(WWindow**)b;
607 if (WTOP(wwin1) > WTOP(wwin2))
608 return -1;
609 else if (WTOP(wwin1) < WTOP(wwin2))
610 return 1;
611 else
612 return 0;
616 static int
617 compareWLeft(const void *a, const void *b)
619 WWindow *wwin1 = *(WWindow**)a;
620 WWindow *wwin2 = *(WWindow**)b;
622 if (WLEFT(wwin1) > WLEFT(wwin2))
623 return -1;
624 else if (WLEFT(wwin1) < WLEFT(wwin2))
625 return 1;
626 else
627 return 0;
631 static int
632 compareWRight(const void *a, const void *b)
634 WWindow *wwin1 = *(WWindow**)a;
635 WWindow *wwin2 = *(WWindow**)b;
637 if (WRIGHT(wwin1) < WRIGHT(wwin2))
638 return -1;
639 else if (WRIGHT(wwin1) > WRIGHT(wwin2))
640 return 1;
641 else
642 return 0;
647 static int
648 compareWBottom(const void *a, const void *b)
650 WWindow *wwin1 = *(WWindow**)a;
651 WWindow *wwin2 = *(WWindow**)b;
653 if (WBOTTOM(wwin1) < WBOTTOM(wwin2))
654 return -1;
655 else if (WBOTTOM(wwin1) > WBOTTOM(wwin2))
656 return 1;
657 else
658 return 0;
662 static void
663 updateResistance(WWindow *wwin, MoveData *data, int newX, int newY)
665 int i;
666 int newX2 = newX + data->winWidth;
667 int newY2 = newY + data->winHeight;
668 Bool ok = False;
670 if (newX < data->realX) {
671 if (data->rightIndex > 0
672 && newX < WRIGHT(data->rightList[data->rightIndex-1])) {
673 ok = True;
674 } else if (data->leftIndex <= data->count-1
675 && newX2 <= WLEFT(data->leftList[data->leftIndex])) {
676 ok = True;
678 } else if (newX > data->realX) {
679 if (data->leftIndex > 0
680 && newX2 > WLEFT(data->leftList[data->leftIndex-1])) {
681 ok = True;
682 } else if (data->rightIndex <= data->count-1
683 && newX >= WRIGHT(data->rightList[data->rightIndex])) {
684 ok = True;
688 if (!ok) {
689 if (newY < data->realY) {
690 if (data->bottomIndex > 0
691 && newY < WBOTTOM(data->bottomList[data->bottomIndex-1])) {
692 ok = True;
693 } else if (data->topIndex <= data->count-1
694 && newY2 <= WTOP(data->topList[data->topIndex])) {
695 ok = True;
697 } else if (newY > data->realY) {
698 if (data->topIndex > 0
699 && newY2 > WTOP(data->topList[data->topIndex-1])) {
700 ok = True;
701 } else if (data->bottomIndex <= data->count-1
702 && newY >= WBOTTOM(data->bottomList[data->bottomIndex])) {
703 ok = True;
708 if (!ok)
709 return;
711 /* TODO: optimize this */
712 if (data->realY < WBOTTOM(data->bottomList[0])) {
713 data->bottomIndex = 0;
715 if (data->realX < WRIGHT(data->rightList[0])) {
716 data->rightIndex = 0;
718 if ((data->realX + data->winWidth) > WLEFT(data->leftList[0])) {
719 data->leftIndex = 0;
721 if ((data->realY + data->winHeight) > WTOP(data->topList[0])) {
722 data->topIndex = 0;
724 for (i = 0; i < data->count; i++) {
725 if (data->realY > WBOTTOM(data->bottomList[i])) {
726 data->bottomIndex = i + 1;
728 if (data->realX > WRIGHT(data->rightList[i])) {
729 data->rightIndex = i + 1;
731 if ((data->realX + data->winWidth) < WLEFT(data->leftList[i])) {
732 data->leftIndex = i + 1;
734 if ((data->realY + data->winHeight) < WTOP(data->topList[i])) {
735 data->topIndex = i + 1;
741 static void
742 freeMoveData(MoveData *data)
744 if (data->topList)
745 wfree(data->topList);
746 if (data->leftList)
747 wfree(data->leftList);
748 if (data->rightList)
749 wfree(data->rightList);
750 if (data->bottomList)
751 wfree(data->bottomList);
755 static void
756 updateMoveData(WWindow *wwin, MoveData *data)
758 WScreen *scr = wwin->screen_ptr;
759 WWindow *tmp;
760 int i;
762 data->count = 0;
763 tmp = scr->focused_window;
764 while (tmp) {
765 if (tmp != wwin && scr->current_workspace == tmp->frame->workspace
766 && !tmp->flags.miniaturized
767 && !tmp->flags.hidden
768 && !tmp->flags.obscured
769 && !WFLAGP(tmp, sunken)) {
770 data->topList[data->count] = tmp;
771 data->leftList[data->count] = tmp;
772 data->rightList[data->count] = tmp;
773 data->bottomList[data->count] = tmp;
774 data->count++;
776 tmp = tmp->prev;
779 if (data->count == 0) {
780 data->topIndex = 0;
781 data->leftIndex = 0;
782 data->rightIndex = 0;
783 data->bottomIndex = 0;
784 return;
788 * order from closest to the border of the screen to farthest
790 qsort(data->topList, data->count, sizeof(WWindow**), compareWTop);
791 qsort(data->leftList, data->count, sizeof(WWindow**), compareWLeft);
792 qsort(data->rightList, data->count, sizeof(WWindow**), compareWRight);
793 qsort(data->bottomList, data->count, sizeof(WWindow**), compareWBottom);
795 /* figure the position of the window relative to the others */
797 data->topIndex = -1;
798 data->leftIndex = -1;
799 data->rightIndex = -1;
800 data->bottomIndex = -1;
802 if (WTOP(wwin) < WBOTTOM(data->bottomList[0])) {
803 data->bottomIndex = 0;
805 if (WLEFT(wwin) < WRIGHT(data->rightList[0])) {
806 data->rightIndex = 0;
808 if (WRIGHT(wwin) > WLEFT(data->leftList[0])) {
809 data->leftIndex = 0;
811 if (WBOTTOM(wwin) > WTOP(data->topList[0])) {
812 data->topIndex = 0;
814 for (i = 0; i < data->count; i++) {
815 if (WTOP(wwin) >= WBOTTOM(data->bottomList[i])) {
816 data->bottomIndex = i + 1;
818 if (WLEFT(wwin) >= WRIGHT(data->rightList[i])) {
819 data->rightIndex = i + 1;
821 if (WRIGHT(wwin) <= WLEFT(data->leftList[i])) {
822 data->leftIndex = i + 1;
824 if (WBOTTOM(wwin) <= WTOP(data->topList[i])) {
825 data->topIndex = i + 1;
831 static void
832 initMoveData(WWindow *wwin, MoveData *data)
834 int i;
835 WWindow *tmp;
837 memset(data, 0, sizeof(MoveData));
839 for (i = 0, tmp = wwin->screen_ptr->focused_window;
840 tmp != NULL;
841 tmp = tmp->prev, i++);
843 if (i > 1) {
844 data->topList = wmalloc(sizeof(WWindow*) * i);
845 data->leftList = wmalloc(sizeof(WWindow*) * i);
846 data->rightList = wmalloc(sizeof(WWindow*) * i);
847 data->bottomList = wmalloc(sizeof(WWindow*) * i);
849 updateMoveData(wwin, data);
852 data->realX = wwin->frame_x;
853 data->realY = wwin->frame_y;
854 data->calcX = wwin->frame_x;
855 data->calcY = wwin->frame_y;
857 data->winWidth = wwin->frame->core->width + 2;
858 data->winHeight = wwin->frame->core->height + 2;
862 static Bool
863 checkWorkspaceChange(WWindow *wwin, MoveData *data, Bool opaqueMove)
865 WScreen *scr = wwin->screen_ptr;
866 Bool changed = False;
868 if (data->mouseX <= 1) {
869 if (scr->current_workspace > 0) {
871 crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace - 1,
872 True);
873 changed = True;
874 data->rubCount = 0;
876 } else if (scr->current_workspace == 0 && wPreferences.ws_cycle) {
878 crossWorkspace(scr, wwin, opaqueMove, scr->workspace_count - 1,
879 True);
880 changed = True;
881 data->rubCount = 0;
883 } else if (data->mouseX >= scr->scr_width - 2) {
885 if (scr->current_workspace == scr->workspace_count - 1) {
887 if (wPreferences.ws_cycle
888 || scr->workspace_count == MAX_WORKSPACES) {
890 crossWorkspace(scr, wwin, opaqueMove, 0, False);
891 changed = True;
892 data->rubCount = 0;
894 /* if user insists on trying to go to next workspace even when
895 * it's already the last, create a new one */
896 else if (data->omouseX == data->mouseX
897 && wPreferences.ws_advance) {
899 /* detect user "rubbing" the window against the edge */
900 if (data->rubCount > 0
901 && data->omouseY - data->mouseY > MOVE_THRESHOLD) {
903 data->rubCount = -(data->rubCount + 1);
905 } else if (data->rubCount <= 0
906 && data->mouseY - data->omouseY > MOVE_THRESHOLD) {
908 data->rubCount = -data->rubCount + 1;
911 /* create a new workspace */
912 if (abs(data->rubCount) > 2) {
913 /* go to next workspace */
914 wWorkspaceNew(scr);
916 crossWorkspace(scr, wwin, opaqueMove,
917 scr->current_workspace+1, False);
918 changed = True;
919 data->rubCount = 0;
921 } else if (scr->current_workspace < scr->workspace_count) {
923 /* go to next workspace */
924 crossWorkspace(scr, wwin, opaqueMove,
925 scr->current_workspace+1, False);
926 changed = True;
927 data->rubCount = 0;
929 } else {
930 data->rubCount = 0;
933 return changed;
937 static void
938 updateWindowPosition(WWindow *wwin, MoveData *data, Bool doResistance,
939 Bool opaqueMove, int newMouseX, int newMouseY)
941 WScreen *scr = wwin->screen_ptr;
942 int dx, dy; /* how much mouse moved */
943 int winL, winR, winT, winB; /* requested new window position */
944 int newX, newY; /* actual new window position */
945 Bool hresist, vresist;
946 Bool updateIndex;
947 Bool attract;
949 hresist = False;
950 vresist = False;
952 updateIndex = False;
954 /* check the direction of the movement */
955 dx = newMouseX - data->mouseX;
956 dy = newMouseY - data->mouseY;
958 data->omouseX = data->mouseX;
959 data->omouseY = data->mouseY;
960 data->mouseX = newMouseX;
961 data->mouseY = newMouseY;
963 winL = data->calcX + dx;
964 winR = data->calcX + data->winWidth + dx;
965 winT = data->calcY + dy;
966 winB = data->calcY + data->winHeight + dy;
968 newX = data->realX;
969 newY = data->realY;
971 if (doResistance) {
972 int l_edge, r_edge;
973 int edge_l, edge_r;
974 int t_edge, b_edge;
975 int edge_t, edge_b;
976 int resist;
978 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
979 attract = wPreferences.attract;
980 /* horizontal movement: check horizontal edge resistances */
981 if (dx || dy) {
982 int i;
983 /* window is the leftmost window: check against screen edge */
984 l_edge = scr->totalUsableArea.x1;
985 r_edge = scr->totalUsableArea.x2 + resist;
986 edge_l = scr->totalUsableArea.x1 - resist;
987 edge_r = scr->totalUsableArea.x2;
989 /* 1 */
990 if ((data->rightIndex >= 0) && (data->rightIndex <= data->count)) {
991 WWindow *looprw;
993 for (i = data->rightIndex - 1; i >= 0; i--) {
994 looprw = data->rightList[i];
995 if (!(data->realY > WBOTTOM(looprw)
996 || (data->realY + data->winHeight) < WTOP(looprw))) {
997 if (attract
998 || ((data->realX < (WRIGHT(looprw) + 2)) && dx < 0)) {
999 l_edge = WRIGHT(looprw) + 1;
1000 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1002 break;
1006 if (attract) {
1007 for (i = data->rightIndex; i < data->count; i++) {
1008 looprw = data->rightList[i];
1009 if(!(data->realY > WBOTTOM(looprw)
1010 || (data->realY + data->winHeight) < WTOP(looprw))) {
1011 r_edge = WRIGHT(looprw) + 1;
1012 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1013 break;
1019 if ((data->leftIndex >= 0) && (data->leftIndex <= data->count)) {
1020 WWindow *looprw;
1022 for (i = data->leftIndex - 1; i >= 0; i--) {
1023 looprw = data->leftList[i];
1024 if (!(data->realY > WBOTTOM(looprw)
1025 || (data->realY + data->winHeight) < WTOP(looprw))) {
1026 if (attract
1027 || (((data->realX + data->winWidth) > (WLEFT(looprw) - 1)) && dx > 0)) {
1028 edge_r = WLEFT(looprw);
1029 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1031 break;
1035 if (attract)
1036 for (i = data->leftIndex; i < data->count; i++) {
1037 looprw = data->leftList[i];
1038 if(!(data->realY > WBOTTOM(looprw)
1039 || (data->realY + data->winHeight) < WTOP(looprw))) {
1040 edge_l = WLEFT(looprw);
1041 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1042 break;
1048 printf("%d %d\n",winL,winR);
1049 printf("l_ %d r_ %d _l %d _r %d\n",l_edge,r_edge,edge_l,edge_r);
1052 if ((winL - l_edge) < (r_edge - winL)) {
1053 if (resist > 0) {
1054 if ((attract && winL <= l_edge + resist && winL >= l_edge - resist)
1055 || (dx < 0 && winL <= l_edge && winL >= l_edge - resist)) {
1056 newX = l_edge;
1057 hresist = True;
1060 } else {
1061 if (resist > 0 && attract && winL >= r_edge - resist && winL <= r_edge + resist) {
1062 newX = r_edge;
1063 hresist = True;
1067 if ((winR - edge_l) < (edge_r - winR)) {
1068 if (resist > 0 && attract && winR <= edge_l + resist && winR >= edge_l - resist) {
1069 newX = edge_l - data->winWidth;
1070 hresist = True;
1072 } else {
1073 if (resist > 0) {
1074 if ((attract && winR >= edge_r - resist && winR <= edge_r + resist)
1075 || (dx > 0 && winR >= edge_r && winR <= edge_r + resist)) {
1076 newX = edge_r - data->winWidth;
1077 hresist = True;
1082 /* VeRT */
1083 t_edge = scr->totalUsableArea.y1;
1084 b_edge = scr->totalUsableArea.y2 + resist;
1085 edge_t = scr->totalUsableArea.y1 - resist;
1086 edge_b = scr->totalUsableArea.y2;
1088 if ((data->bottomIndex >= 0) && (data->bottomIndex <= data->count)) {
1089 WWindow *looprw;
1091 for (i = data->bottomIndex - 1; i >= 0; i--) {
1092 looprw = data->bottomList[i];
1093 if (!(data->realX > WRIGHT(looprw)
1094 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1095 if (attract
1096 || ((data->realY < (WBOTTOM(looprw) + 2)) && dy < 0)) {
1097 t_edge = WBOTTOM(looprw) + 1;
1098 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1100 break;
1104 if (attract) {
1105 for (i = data->bottomIndex; i < data->count; i++) {
1106 looprw = data->bottomList[i];
1107 if(!(data->realX > WRIGHT(looprw)
1108 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1109 b_edge = WBOTTOM(looprw) + 1;
1110 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1111 break;
1117 if ((data->topIndex >= 0) && (data->topIndex <= data->count)) {
1118 WWindow *looprw;
1120 for (i = data->topIndex - 1; i >= 0; i--) {
1121 looprw = data->topList[i];
1122 if (!(data->realX > WRIGHT(looprw)
1123 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1124 if (attract
1125 || (((data->realY + data->winHeight) > (WTOP(looprw) - 1)) && dy > 0)) {
1126 edge_b = WTOP(looprw);
1127 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1129 break;
1133 if (attract)
1134 for (i = data->topIndex; i < data->count; i++) {
1135 looprw = data->topList[i];
1136 if(!(data->realX > WRIGHT(looprw)
1137 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1138 edge_t = WTOP(looprw);
1139 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1140 break;
1145 if ((winT - t_edge) < (b_edge - winT)) {
1146 if (resist > 0) {
1147 if ((attract && winT <= t_edge + resist && winT >= t_edge - resist)
1148 || (dy < 0 && winT <= t_edge && winT >= t_edge - resist)) {
1149 newY = t_edge;
1150 vresist = True;
1154 else {
1155 if (resist > 0 && attract && winT >= b_edge - resist && winT <= b_edge + resist) {
1156 newY = b_edge;
1157 vresist = True;
1161 if ((winB - edge_t) < (edge_b - winB)) {
1162 if (resist > 0 && attract && winB <= edge_t + resist && winB >= edge_t - resist) {
1163 newY = edge_t - data->winHeight;
1164 vresist = True;
1167 else {
1168 if (resist > 0) {
1169 if ((attract && winB >= edge_b - resist && winB <= edge_b + resist)
1170 || (dy > 0 && winB >= edge_b && winB <= edge_b + resist)) {
1171 newY = edge_b - data->winHeight;
1172 vresist = True;
1177 /* END VeRT */
1181 /* update window position */
1182 data->calcX += dx;
1183 data->calcY += dy;
1185 if (((dx > 0 && data->calcX - data->realX > 0)
1186 || (dx < 0 && data->calcX - data->realX < 0)) && !hresist)
1187 newX = data->calcX;
1189 if (((dy > 0 && data->calcY - data->realY > 0)
1190 || (dy < 0 && data->calcY - data->realY < 0)) && !vresist)
1191 newY = data->calcY;
1193 if (data->realX != newX || data->realY != newY) {
1195 if (wPreferences.move_display == WDIS_NEW
1196 && !scr->selected_windows) {
1197 showPosition(wwin, data->realX, data->realY);
1199 if (opaqueMove) {
1200 doWindowMove(wwin, scr->selected_windows,
1201 newX - wwin->frame_x,
1202 newY - wwin->frame_y);
1203 } else {
1204 /* erase frames */
1205 drawFrames(wwin, scr->selected_windows,
1206 data->realX - wwin->frame_x,
1207 data->realY - wwin->frame_y);
1210 if (!scr->selected_windows
1211 && wPreferences.move_display == WDIS_FRAME_CENTER) {
1213 moveGeometryDisplayCentered(scr, newX + data->winWidth/2,
1214 newY + data->winHeight/2);
1217 if (!opaqueMove) {
1218 /* draw frames */
1219 drawFrames(wwin, scr->selected_windows,
1220 newX - wwin->frame_x,
1221 newY - wwin->frame_y);
1224 if (!scr->selected_windows) {
1225 showPosition(wwin, newX, newY);
1230 /* recalc relative window position */
1231 if (doResistance && (data->realX != newX || data->realY != newY)) {
1232 updateResistance(wwin, data, newX, newY);
1235 data->realX = newX;
1236 data->realY = newY;
1240 #define _KS KEY_CONTROL_WINDOW_WEIGHT
1243 wKeyboardMoveResizeWindow(WWindow *wwin)
1245 WScreen *scr = wwin->screen_ptr;
1246 Window root = scr->root_win;
1247 XEvent event;
1248 int w = wwin->frame->core->width;
1249 int h = wwin->frame->core->height;
1250 int scr_width = wwin->screen_ptr->scr_width;
1251 int scr_height = wwin->screen_ptr->scr_height;
1252 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1253 int src_x = wwin->frame_x;
1254 int src_y = wwin->frame_y;
1255 int done,off_x,off_y,ww,wh;
1256 int kspeed = _KS;
1257 Time lastTime = 0;
1258 KeySym keysym=NoSymbol;
1259 int moment=0;
1260 KeyCode shiftl,shiftr,ctrll,ctrlmode;
1262 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1263 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1264 ctrll = XKeysymToKeycode(dpy, XK_Control_L);
1265 ctrlmode=done=off_x=off_y=0;
1267 XSync(dpy, False);
1268 wusleep(10000);
1269 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1271 if (!wwin->flags.selected) {
1272 wUnselectWindows(scr);
1274 XGrabServer(dpy);
1275 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
1276 |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
1277 GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime);
1279 if (wwin->flags.shaded || scr->selected_windows) {
1280 if(scr->selected_windows)
1281 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1282 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1283 if(!scr->selected_windows)
1284 mapPositionDisplay(wwin, src_x, src_y, w, h);
1285 } else {
1286 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1288 ww=w;
1289 wh=h;
1290 while(1) {
1292 looper.ox=off_x;
1293 looper.oy=off_y;
1295 do {
1296 WMMaskEvent(dpy, KeyPressMask | ButtonReleaseMask
1297 | ButtonPressMask | ExposureMask, &event);
1298 if (event.type == Expose) {
1299 WMHandleEvent(&event);
1301 } while (event.type == Expose);
1304 if (wwin->flags.shaded || scr->selected_windows) {
1305 if(scr->selected_windows)
1306 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1307 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1308 /*** I HATE EDGE RESISTANCE - ]d ***/
1310 else {
1311 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
1314 if(ctrlmode)
1315 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
1317 XUngrabServer(dpy);
1318 XSync(dpy, False);
1320 switch (event.type) {
1321 case KeyPress:
1322 /* accelerate */
1323 if (event.xkey.time - lastTime > 50) {
1324 kspeed/=(1 + (event.xkey.time - lastTime)/100);
1325 } else {
1326 if (kspeed < 20) {
1327 kspeed++;
1330 if (kspeed < _KS) kspeed = _KS;
1331 lastTime = event.xkey.time;
1333 if (event.xkey.state & ControlMask && !wwin->flags.shaded) {
1334 ctrlmode=1;
1335 wUnselectWindows(scr);
1337 else {
1338 ctrlmode=0;
1340 if (event.xkey.keycode == shiftl || event.xkey.keycode == shiftr) {
1341 if (ctrlmode)
1342 cycleGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh, 0);
1343 else
1344 cyclePositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
1346 else {
1348 keysym = XLookupKeysym(&event.xkey, 0);
1349 switch (keysym) {
1350 case XK_Return:
1351 done=2;
1352 break;
1353 case XK_Escape:
1354 done=1;
1355 break;
1356 case XK_Up:
1357 #ifdef XK_KP_Up
1358 case XK_KP_Up:
1359 #endif
1360 case XK_k:
1361 if (ctrlmode){
1362 if (moment != UP)
1363 h = wh;
1364 h-=kspeed;
1365 moment = UP;
1366 if (h < 1) h = 1;
1368 else off_y-=kspeed;
1369 break;
1370 case XK_Down:
1371 #ifdef XK_KP_Down
1372 case XK_KP_Down:
1373 #endif
1374 case XK_j:
1375 if (ctrlmode){
1376 if (moment != DOWN)
1377 h = wh;
1378 h+=kspeed;
1379 moment = DOWN;
1381 else off_y+=kspeed;
1382 break;
1383 case XK_Left:
1384 #ifdef XK_KP_Left
1385 case XK_KP_Left:
1386 #endif
1387 case XK_h:
1388 if (ctrlmode) {
1389 if (moment != LEFT)
1390 w = ww;
1391 w-=kspeed;
1392 if (w < 1) w = 1;
1393 moment = LEFT;
1395 else off_x-=kspeed;
1396 break;
1397 case XK_Right:
1398 #ifdef XK_KP_Right
1399 case XK_KP_Right:
1400 #endif
1401 case XK_l:
1402 if (ctrlmode) {
1403 if (moment != RIGHT)
1404 w = ww;
1405 w+=kspeed;
1406 moment = RIGHT;
1408 else off_x+=kspeed;
1409 break;
1412 ww=w;wh=h;
1413 wh-=vert_border;
1414 wWindowConstrainSize(wwin, &ww, &wh);
1415 wh+=vert_border;
1417 if (wPreferences.ws_cycle){
1418 if (src_x + off_x + ww < 20){
1419 if(!scr->current_workspace) {
1420 wWorkspaceChange(scr, scr->workspace_count-1);
1422 else wWorkspaceChange(scr, scr->current_workspace-1);
1423 off_x += scr_width;
1425 else if (src_x + off_x + 20 > scr_width){
1426 if(scr->current_workspace == scr->workspace_count-1) {
1427 wWorkspaceChange(scr, 0);
1429 else wWorkspaceChange(scr, scr->current_workspace+1);
1430 off_x -= scr_width;
1433 else {
1434 if (src_x + off_x + ww < 20)
1435 off_x = 20 - ww - src_x;
1436 else if (src_x + off_x + 20 > scr_width)
1437 off_x = scr_width - 20 - src_x;
1440 if (src_y + off_y + wh < 20) {
1441 off_y = 20 - wh - src_y;
1443 else if (src_y + off_y + 20 > scr_height) {
1444 off_y = scr_height - 20 - src_y;
1447 break;
1448 case ButtonPress:
1449 case ButtonRelease:
1450 done=1;
1451 break;
1452 case Expose:
1453 WMHandleEvent(&event);
1454 while (XCheckTypedEvent(dpy, Expose, &event)) {
1455 WMHandleEvent(&event);
1457 break;
1459 default:
1460 WMHandleEvent(&event);
1461 break;
1464 XGrabServer(dpy);
1465 /*xxx*/
1467 if (wwin->flags.shaded && !scr->selected_windows){
1468 moveGeometryDisplayCentered(scr, src_x+off_x + w/2, src_y+off_y + h/2);
1469 } else {
1470 if (ctrlmode) {
1471 WMUnmapWidget(scr->gview);
1472 mapGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
1473 } else if(!scr->selected_windows) {
1474 WMUnmapWidget(scr->gview);
1475 mapPositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
1479 if (wwin->flags.shaded || scr->selected_windows) {
1480 if (scr->selected_windows)
1481 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1482 else
1483 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1484 } else {
1485 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
1489 if (ctrlmode) {
1490 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
1491 } else if(!scr->selected_windows)
1492 showPosition(wwin, src_x+off_x, src_y+off_y);
1493 /**/
1495 if (done) {
1496 scr->keymove_tick=0;
1498 WMDeleteTimerWithClientData(&looper);
1500 if (wwin->flags.shaded || scr->selected_windows) {
1501 if(scr->selected_windows)
1502 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1503 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1505 else {
1506 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
1509 if (ctrlmode) {
1510 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
1511 WMUnmapWidget(scr->gview);
1512 } else
1513 WMUnmapWidget(scr->gview);
1515 XUngrabKeyboard(dpy, CurrentTime);
1516 XUngrabPointer(dpy, CurrentTime);
1517 XUngrabServer(dpy);
1519 if(done==2) {
1520 if (wwin->flags.shaded || scr->selected_windows) {
1521 if (!scr->selected_windows) {
1522 wWindowMove(wwin, src_x+off_x, src_y+off_y);
1523 wWindowSynthConfigureNotify(wwin);
1524 } else {
1525 WMArrayIterator iter;
1526 WWindow *foo;
1528 doWindowMove(wwin, scr->selected_windows, off_x, off_y);
1530 WM_ITERATE_ARRAY(scr->selected_windows, foo, iter) {
1531 wWindowSynthConfigureNotify(foo);
1534 } else {
1535 if (wwin->client.width != ww)
1536 wwin->flags.user_changed_width = 1;
1538 if (wwin->client.height != wh - vert_border)
1539 wwin->flags.user_changed_height = 1;
1541 wWindowConfigure(wwin, src_x+off_x, src_y+off_y,
1542 ww, wh - vert_border);
1543 wWindowSynthConfigureNotify(wwin);
1545 wWindowChangeWorkspace(wwin, scr->current_workspace);
1546 wSetFocusTo(scr, wwin);
1548 return 1;
1555 *----------------------------------------------------------------------
1556 * wMouseMoveWindow--
1557 * Move the named window and the other selected ones (if any),
1558 * interactively. Also shows the position of the window, if only one
1559 * window is being moved.
1560 * If the window is not on the selected window list, the selected
1561 * windows are deselected.
1562 * If shift is pressed during the operation, the position display
1563 * is changed to another type.
1565 * Returns:
1566 * True if the window was moved, False otherwise.
1568 * Side effects:
1569 * The window(s) position is changed, and the client(s) are
1570 * notified about that.
1571 * The position display configuration may be changed.
1572 *----------------------------------------------------------------------
1575 wMouseMoveWindow(WWindow *wwin, XEvent *ev)
1577 WScreen *scr = wwin->screen_ptr;
1578 XEvent event;
1579 Window root = scr->root_win;
1580 KeyCode shiftl, shiftr;
1581 Bool done = False;
1582 int started = 0;
1583 int warped = 0;
1584 /* This needs not to change while moving, else bad things can happen */
1585 int opaqueMove = wPreferences.opaque_move;
1586 MoveData moveData;
1587 #ifdef GHOST_WINDOW_MOVE
1588 RImage *rimg;
1590 rimg = InitGhostWindowMove(scr);
1591 #endif
1594 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1595 XSetWindowAttributes attr;
1597 attr.save_under = True;
1598 XChangeWindowAttributes(dpy, wwin->frame->core->window,
1599 CWSaveUnder, &attr);
1603 initMoveData(wwin, &moveData);
1605 moveData.mouseX = ev->xmotion.x_root;
1606 moveData.mouseY = ev->xmotion.y_root;
1608 if (!wwin->flags.selected) {
1609 /* this window is not selected, unselect others and move only wwin */
1610 wUnselectWindows(scr);
1612 #ifdef DEBUG
1613 puts("Moving window");
1614 #endif
1615 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1616 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1617 while (!done) {
1618 if (warped) {
1619 int junk;
1620 Window junkw;
1622 /* XWarpPointer() doesn't seem to generate Motion events, so
1623 we've got to simulate them */
1624 XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
1625 &event.xmotion.y_root, &junk, &junk,
1626 (unsigned *) &junk);
1627 } else {
1628 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
1629 | PointerMotionHintMask
1630 | ButtonReleaseMask | ButtonPressMask | ExposureMask,
1631 &event);
1633 if (event.type == MotionNotify) {
1634 /* compress MotionNotify events */
1635 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
1636 if (!checkMouseSamplingRate(&event))
1637 continue;
1640 switch (event.type) {
1641 case KeyPress:
1642 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1643 && started && !scr->selected_windows) {
1645 if (!opaqueMove) {
1646 drawFrames(wwin, scr->selected_windows,
1647 moveData.realX - wwin->frame_x,
1648 moveData.realY - wwin->frame_y);
1651 if (wPreferences.move_display == WDIS_NEW
1652 && !scr->selected_windows) {
1653 showPosition(wwin, moveData.realX, moveData.realY);
1654 XUngrabServer(dpy);
1656 cyclePositionDisplay(wwin, moveData.realX, moveData.realY,
1657 moveData.winWidth, moveData.winHeight);
1659 if (wPreferences.move_display == WDIS_NEW
1660 && !scr->selected_windows) {
1661 XGrabServer(dpy);
1662 showPosition(wwin, moveData.realX, moveData.realY);
1665 if (!opaqueMove) {
1666 drawFrames(wwin, scr->selected_windows,
1667 moveData.realX - wwin->frame_x,
1668 moveData.realY - wwin->frame_y);
1670 /*} else {
1671 WMHandleEvent(&event); this causes problems needs fixing */
1673 break;
1675 case MotionNotify:
1676 if (started) {
1677 updateWindowPosition(wwin, &moveData,
1678 scr->selected_windows == NULL
1679 && wPreferences.edge_resistance > 0,
1680 opaqueMove,
1681 event.xmotion.x_root,
1682 event.xmotion.y_root);
1684 if (!warped && !wPreferences.no_autowrap) {
1685 int oldWorkspace = scr->current_workspace;
1687 if (wPreferences.move_display == WDIS_NEW
1688 && !scr->selected_windows) {
1689 showPosition(wwin, moveData.realX, moveData.realY);
1690 XUngrabServer(dpy);
1692 if (!opaqueMove) {
1693 drawFrames(wwin, scr->selected_windows,
1694 moveData.realX - wwin->frame_x,
1695 moveData.realY - wwin->frame_y);
1697 if (checkWorkspaceChange(wwin, &moveData, opaqueMove)) {
1698 if (scr->current_workspace != oldWorkspace
1699 && wPreferences.edge_resistance > 0
1700 && scr->selected_windows == NULL)
1701 updateMoveData(wwin, &moveData);
1702 warped = 1;
1704 if (!opaqueMove) {
1705 drawFrames(wwin, scr->selected_windows,
1706 moveData.realX - wwin->frame_x,
1707 moveData.realY - wwin->frame_y);
1709 if (wPreferences.move_display == WDIS_NEW
1710 && !scr->selected_windows) {
1711 XSync(dpy, False);
1712 showPosition(wwin, moveData.realX, moveData.realY);
1713 XGrabServer(dpy);
1715 } else {
1716 warped = 0;
1718 } else if (abs(ev->xmotion.x_root - event.xmotion.x_root) >= MOVE_THRESHOLD
1719 || abs(ev->xmotion.y_root - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1721 XChangeActivePointerGrab(dpy, ButtonMotionMask
1722 | ButtonReleaseMask | ButtonPressMask,
1723 wCursor[WCUR_MOVE], CurrentTime);
1724 started = 1;
1725 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
1726 CurrentTime);
1728 if (!scr->selected_windows)
1729 mapPositionDisplay(wwin, moveData.realX, moveData.realY,
1730 moveData.winWidth, moveData.winHeight);
1732 if (started && !opaqueMove)
1733 drawFrames(wwin, scr->selected_windows, 0, 0);
1735 if (!opaqueMove || (wPreferences.move_display==WDIS_NEW
1736 && !scr->selected_windows)) {
1737 XGrabServer(dpy);
1738 if (wPreferences.move_display==WDIS_NEW)
1739 showPosition(wwin, moveData.realX, moveData.realY);
1742 break;
1744 case ButtonPress:
1745 break;
1747 case ButtonRelease:
1748 if (event.xbutton.button != ev->xbutton.button)
1749 break;
1751 if (started) {
1752 XEvent e;
1753 if (!opaqueMove) {
1754 drawFrames(wwin, scr->selected_windows,
1755 moveData.realX - wwin->frame_x,
1756 moveData.realY - wwin->frame_y);
1757 XSync(dpy, 0);
1758 doWindowMove(wwin, scr->selected_windows,
1759 moveData.realX - wwin->frame_x,
1760 moveData.realY - wwin->frame_y);
1762 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
1763 wWindowSynthConfigureNotify(wwin);
1764 #endif
1765 XUngrabKeyboard(dpy, CurrentTime);
1766 XUngrabServer(dpy);
1767 if (!opaqueMove) {
1768 wWindowChangeWorkspace(wwin, scr->current_workspace);
1769 wSetFocusTo(scr, wwin);
1771 if (wPreferences.move_display == WDIS_NEW)
1772 showPosition(wwin, moveData.realX, moveData.realY);
1774 /* discard all enter/leave events that happened until
1775 * the time the button was released */
1776 while (XCheckTypedEvent(dpy, EnterNotify, &e)) {
1777 if (e.xcrossing.time > event.xbutton.time) {
1778 XPutBackEvent(dpy, &e);
1779 break;
1782 while (XCheckTypedEvent(dpy, LeaveNotify, &e)) {
1783 if (e.xcrossing.time > event.xbutton.time) {
1784 XPutBackEvent(dpy, &e);
1785 break;
1789 if (!scr->selected_windows) {
1790 /* get rid of the geometry window */
1791 WMUnmapWidget(scr->gview);
1794 #ifdef DEBUG
1795 puts("End move window");
1796 #endif
1797 done = True;
1798 break;
1800 default:
1801 if (started && !opaqueMove) {
1802 drawFrames(wwin, scr->selected_windows,
1803 moveData.realX - wwin->frame_x,
1804 moveData.realY - wwin->frame_y);
1805 XUngrabServer(dpy);
1806 WMHandleEvent(&event);
1807 XSync(dpy, False);
1808 XGrabServer(dpy);
1809 drawFrames(wwin, scr->selected_windows,
1810 moveData.realX - wwin->frame_x,
1811 moveData.realY - wwin->frame_y);
1812 } else {
1813 WMHandleEvent(&event);
1815 break;
1819 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1820 XSetWindowAttributes attr;
1823 attr.save_under = False;
1824 XChangeWindowAttributes(dpy, wwin->frame->core->window,
1825 CWSaveUnder, &attr);
1829 freeMoveData(&moveData);
1831 return started;
1835 #define RESIZEBAR 1
1836 #define HCONSTRAIN 2
1838 static int
1839 getResizeDirection(WWindow *wwin, int x, int y, int dx, int dy,
1840 int flags)
1842 int w = wwin->frame->core->width - 1;
1843 int cw = wwin->frame->resizebar_corner_width;
1844 int dir;
1846 /* if not resizing through the resizebar */
1847 if (!(flags & RESIZEBAR)) {
1848 int xdir = (abs(x) < (wwin->client.width/2)) ? LEFT : RIGHT;
1849 int ydir = (abs(y) < (wwin->client.height/2)) ? UP : DOWN;
1850 if (abs(dx) < 2 || abs(dy) < 2) {
1851 if (abs(dy) > abs(dx))
1852 xdir = 0;
1853 else
1854 ydir = 0;
1856 return (xdir | ydir);
1859 /* window is too narrow. allow diagonal resize */
1860 if (cw * 2 >= w) {
1861 int ydir;
1863 if (flags & HCONSTRAIN)
1864 ydir = 0;
1865 else
1866 ydir = DOWN;
1867 if (x < cw)
1868 return (LEFT | ydir);
1869 else
1870 return (RIGHT | ydir);
1872 /* vertical resize */
1873 if ((x > cw) && (x < w - cw))
1874 return DOWN;
1876 if (x < cw)
1877 dir = LEFT;
1878 else
1879 dir = RIGHT;
1881 if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
1882 dir |= DOWN;
1884 return dir;
1888 void
1889 wMouseResizeWindow(WWindow *wwin, XEvent *ev)
1891 XEvent event;
1892 WScreen *scr = wwin->screen_ptr;
1893 Window root = scr->root_win;
1894 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1895 int fw = wwin->frame->core->width;
1896 int fh = wwin->frame->core->height;
1897 int fx = wwin->frame_x;
1898 int fy = wwin->frame_y;
1899 int is_resizebar = (wwin->frame->resizebar
1900 && ev->xany.window==wwin->frame->resizebar->window);
1901 int orig_x, orig_y;
1902 int started;
1903 int dw, dh;
1904 int rw = fw, rh = fh;
1905 int rx1, ry1, rx2, ry2;
1906 int res = 0;
1907 KeyCode shiftl, shiftr;
1908 int h = 0;
1909 int orig_fx = fx;
1910 int orig_fy = fy;
1911 int orig_fw = fw;
1912 int orig_fh = fh;
1914 if (wwin->flags.shaded) {
1915 wwarning("internal error: tryein");
1916 return;
1918 orig_x = ev->xbutton.x_root;
1919 orig_y = ev->xbutton.y_root;
1921 started = 0;
1922 #ifdef DEBUG
1923 puts("Resizing window");
1924 #endif
1926 wUnselectWindows(scr);
1927 rx1 = fx;
1928 rx2 = fx + fw - 1;
1929 ry1 = fy;
1930 ry2 = fy + fh - 1;
1931 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1932 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1933 if (!WFLAGP(wwin, no_titlebar))
1934 h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
1935 else
1936 h = 0;
1937 while (1) {
1938 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
1939 | ButtonReleaseMask | PointerMotionHintMask
1940 | ButtonPressMask | ExposureMask, &event);
1941 if (!checkMouseSamplingRate(&event))
1942 continue;
1944 switch (event.type) {
1945 case KeyPress:
1946 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1947 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1948 && started) {
1949 drawTransparentFrame(wwin, fx, fy, fw, fh);
1950 cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
1951 drawTransparentFrame(wwin, fx, fy, fw, fh);
1953 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1954 break;
1956 case MotionNotify:
1957 if (started) {
1958 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
1960 dw = 0;
1961 dh = 0;
1963 orig_fx = fx;
1964 orig_fy = fy;
1965 orig_fw = fw;
1966 orig_fh = fh;
1968 if (res & LEFT)
1969 dw = orig_x - event.xmotion.x_root;
1970 else if (res & RIGHT)
1971 dw = event.xmotion.x_root - orig_x;
1972 if (res & UP)
1973 dh = orig_y - event.xmotion.y_root;
1974 else if (res & DOWN)
1975 dh = event.xmotion.y_root - orig_y;
1977 orig_x = event.xmotion.x_root;
1978 orig_y = event.xmotion.y_root;
1980 rw += dw;
1981 rh += dh;
1982 fw = rw;
1983 fh = rh - vert_border;
1984 wWindowConstrainSize(wwin, &fw, &fh);
1985 fh += vert_border;
1986 if (res & LEFT)
1987 fx = rx2 - fw + 1;
1988 else if (res & RIGHT)
1989 fx = rx1;
1990 if (res & UP)
1991 fy = ry2 - fh + 1;
1992 else if (res & DOWN)
1993 fy = ry1;
1994 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
1995 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1996 int tx, ty;
1997 Window junkw;
1998 int flags;
2000 XTranslateCoordinates(dpy, root, wwin->frame->core->window,
2001 orig_x, orig_y, &tx, &ty, &junkw);
2003 /* check if resizing through resizebar */
2004 if (is_resizebar)
2005 flags = RESIZEBAR;
2006 else
2007 flags = 0;
2009 if (is_resizebar && ((ev->xbutton.state & ShiftMask)
2010 || abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
2011 flags |= HCONSTRAIN;
2013 res = getResizeDirection(wwin, tx, ty,
2014 orig_x - event.xmotion.x_root,
2015 orig_y - event.xmotion.y_root, flags);
2017 if (res == (UP|LEFT))
2018 XChangeActivePointerGrab(dpy, ButtonMotionMask
2019 | ButtonReleaseMask | ButtonPressMask,
2020 wCursor[WCUR_TOPLEFTRESIZE], CurrentTime);
2021 else if (res == (UP|RIGHT))
2022 XChangeActivePointerGrab(dpy, ButtonMotionMask
2023 | ButtonReleaseMask | ButtonPressMask,
2024 wCursor[WCUR_TOPRIGHTRESIZE], CurrentTime);
2025 else if (res == (DOWN|LEFT))
2026 XChangeActivePointerGrab(dpy, ButtonMotionMask
2027 | ButtonReleaseMask | ButtonPressMask,
2028 wCursor[WCUR_BOTTOMLEFTRESIZE], CurrentTime);
2029 else if (res == (DOWN|RIGHT))
2030 XChangeActivePointerGrab(dpy, ButtonMotionMask
2031 | ButtonReleaseMask | ButtonPressMask,
2032 wCursor[WCUR_BOTTOMRIGHTRESIZE], CurrentTime);
2033 else if (res == DOWN || res == UP)
2034 XChangeActivePointerGrab(dpy, ButtonMotionMask
2035 | ButtonReleaseMask | ButtonPressMask,
2036 wCursor[WCUR_VERTICALRESIZE], CurrentTime);
2037 else if (res & (DOWN|UP))
2038 XChangeActivePointerGrab(dpy, ButtonMotionMask
2039 | ButtonReleaseMask | ButtonPressMask,
2040 wCursor[WCUR_VERTICALRESIZE], CurrentTime);
2041 else if (res & (LEFT|RIGHT))
2042 XChangeActivePointerGrab(dpy, ButtonMotionMask
2043 | ButtonReleaseMask | ButtonPressMask,
2044 wCursor[WCUR_HORIZONRESIZE], CurrentTime);
2046 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
2047 CurrentTime);
2049 XGrabServer(dpy);
2051 /* Draw the resize frame for the first time. */
2052 mapGeometryDisplay(wwin, fx, fy, fw, fh);
2054 drawTransparentFrame(wwin, fx, fy, fw, fh);
2056 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2058 started = 1;
2060 if (started) {
2061 if (wPreferences.size_display == WDIS_FRAME_CENTER) {
2062 drawTransparentFrame(wwin, orig_fx, orig_fy,
2063 orig_fw, orig_fh);
2064 moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
2065 drawTransparentFrame(wwin, fx, fy, fw, fh);
2066 } else {
2067 drawTransparentFrame(wwin, orig_fx, orig_fy,
2068 orig_fw, orig_fh);
2069 drawTransparentFrame(wwin, fx, fy, fw, fh);
2071 if (fh != orig_fh || fw != orig_fw) {
2072 if (wPreferences.size_display == WDIS_NEW) {
2073 showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw,
2074 orig_fy + orig_fh, res);
2076 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2079 break;
2081 case ButtonPress:
2082 break;
2084 case ButtonRelease:
2085 if (event.xbutton.button != ev->xbutton.button)
2086 break;
2088 if (started) {
2089 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2091 drawTransparentFrame(wwin, fx, fy, fw, fh);
2093 XUngrabKeyboard(dpy, CurrentTime);
2094 WMUnmapWidget(scr->gview);
2095 XUngrabServer(dpy);
2097 if (wwin->client.width != fw)
2098 wwin->flags.user_changed_width = 1;
2100 if (wwin->client.height != fh - vert_border)
2101 wwin->flags.user_changed_height = 1;
2103 wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
2105 #ifdef DEBUG
2106 puts("End resize window");
2107 #endif
2108 return;
2110 default:
2111 WMHandleEvent(&event);
2116 #undef LEFT
2117 #undef RIGHT
2118 #undef HORIZONTAL
2119 #undef UP
2120 #undef DOWN
2121 #undef VERTICAL
2122 #undef HCONSTRAIN
2123 #undef RESIZEBAR
2125 void
2126 wUnselectWindows(WScreen *scr)
2128 WWindow *wwin;
2130 if (!scr->selected_windows)
2131 return;
2133 while (WMGetArrayItemCount(scr->selected_windows)) {
2134 wwin = WMGetFromArray(scr->selected_windows, 0);
2135 if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
2136 wIconSelect(wwin->icon);
2138 wSelectWindow(wwin, False);
2140 WMFreeArray(scr->selected_windows);
2141 scr->selected_windows = NULL;
2144 #ifndef LITE
2145 static void
2146 selectWindowsInside(WScreen *scr, int x1, int y1, int x2, int y2)
2148 WWindow *tmpw;
2150 /* select the windows and put them in the selected window list */
2151 tmpw = scr->focused_window;
2152 while (tmpw != NULL) {
2153 if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
2154 if ((tmpw->frame->workspace == scr->current_workspace
2155 || IS_OMNIPRESENT(tmpw))
2156 && (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1)
2157 && (tmpw->frame->core->width + tmpw->frame_x <= x2)
2158 && (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
2159 wSelectWindow(tmpw, True);
2162 tmpw = tmpw->prev;
2167 void
2168 wSelectWindows(WScreen *scr, XEvent *ev)
2170 XEvent event;
2171 Window root = scr->root_win;
2172 GC gc = scr->frame_gc;
2173 int xp = ev->xbutton.x_root;
2174 int yp = ev->xbutton.y_root;
2175 int w = 0, h = 0;
2176 int x = xp, y = yp;
2178 #ifdef DEBUG
2179 puts("Selecting windows");
2180 #endif
2181 if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
2182 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
2183 GrabModeAsync, None, wCursor[WCUR_DEFAULT],
2184 CurrentTime) != Success) {
2185 return;
2187 XGrabServer(dpy);
2189 wUnselectWindows(scr);
2191 XDrawRectangle(dpy, root, gc, xp, yp, w, h);
2192 while (1) {
2193 WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask
2194 | ButtonPressMask, &event);
2196 switch (event.type) {
2197 case MotionNotify:
2198 XDrawRectangle(dpy, root, gc, x, y, w, h);
2199 x = event.xmotion.x_root;
2200 if (x < xp) {
2201 w = xp - x;
2202 } else {
2203 w = x - xp;
2204 x = xp;
2206 y = event.xmotion.y_root;
2207 if (y < yp) {
2208 h = yp - y;
2209 } else {
2210 h = y - yp;
2211 y = yp;
2213 XDrawRectangle(dpy, root, gc, x, y, w, h);
2214 break;
2216 case ButtonPress:
2217 break;
2219 case ButtonRelease:
2220 if (event.xbutton.button != ev->xbutton.button)
2221 break;
2223 XDrawRectangle(dpy, root, gc, x, y, w, h);
2224 XUngrabServer(dpy);
2225 XUngrabPointer(dpy, CurrentTime);
2226 selectWindowsInside(scr, x, y, x + w, y + h);
2228 #ifdef KWM_HINTS
2229 wKWMSelectRootRegion(scr, xp, yp, w, h,
2230 event.xbutton.state & ControlMask);
2231 #endif /* KWM_HINTS */
2233 #ifdef DEBUG
2234 puts("End window selection");
2235 #endif
2236 return;
2238 default:
2239 WMHandleEvent(&event);
2240 break;
2244 #endif /* !LITE */
2246 void
2247 InteractivePlaceWindow(WWindow *wwin, int *x_ret, int *y_ret,
2248 unsigned width, unsigned height)
2250 WScreen *scr = wwin->screen_ptr;
2251 Window root = scr->root_win;
2252 int x, y, h = 0;
2253 XEvent event;
2254 KeyCode shiftl, shiftr;
2255 Window junkw;
2256 int junk;
2258 if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
2259 GrabModeAsync, GrabModeAsync, None,
2260 wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
2261 *x_ret = 0;
2262 *y_ret = 0;
2263 return;
2265 if (!WFLAGP(wwin, no_titlebar)) {
2266 h = WMFontHeight(scr->title_font) + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
2267 height += h;
2269 if (!WFLAGP(wwin, no_resizebar)) {
2270 height += RESIZEBAR_HEIGHT;
2272 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
2273 XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk,
2274 (unsigned *) &junk);
2275 mapPositionDisplay(wwin, x - width/2, y - h/2, width, height);
2277 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2279 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
2280 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
2281 while (1) {
2282 WMMaskEvent(dpy, PointerMotionMask|ButtonPressMask|ExposureMask|KeyPressMask,
2283 &event);
2285 if (!checkMouseSamplingRate(&event))
2286 continue;
2288 switch (event.type) {
2289 case KeyPress:
2290 if ((event.xkey.keycode == shiftl)
2291 || (event.xkey.keycode == shiftr)) {
2292 drawTransparentFrame(wwin,
2293 x - width/2, y - h/2, width, height);
2294 cyclePositionDisplay(wwin,
2295 x - width/2, y - h/2, width, height);
2296 drawTransparentFrame(wwin,
2297 x - width/2, y - h/2, width, height);
2299 break;
2301 case MotionNotify:
2302 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2304 x = event.xmotion.x_root;
2305 y = event.xmotion.y_root;
2307 if (wPreferences.move_display == WDIS_FRAME_CENTER)
2308 moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
2310 showPosition(wwin, x - width/2, y - h/2);
2312 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2314 break;
2316 case ButtonPress:
2317 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2318 XSync(dpy, 0);
2319 *x_ret = x - width/2;
2320 *y_ret = y - h/2;
2321 XUngrabPointer(dpy, CurrentTime);
2322 XUngrabKeyboard(dpy, CurrentTime);
2323 /* get rid of the geometry window */
2324 WMUnmapWidget(scr->gview);
2325 return;
2327 default:
2328 WMHandleEvent(&event);
2329 break;