change x to xp and y to yp by guessing, hope it is correct.
[wmaker-crm.git] / src / moveres.c
blobabf3b47bdbd6c0006d6b62dbefe1948d66f30107
1 /*
2 * Window Maker window manager
3 *
4 * Copyright (c) 1997, 1998, 1999 Alfredo K. Kojima
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
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"
44 #ifdef KWM_HINTS
45 #include "kwm.h"
46 #endif
48 /* How many different types of geometry/position
49 display thingies are there? */
50 #define NUM_DISPLAYS 4
52 #define LEFT 1
53 #define RIGHT 2
54 #define HORIZONTAL (LEFT|RIGHT)
55 #define UP 4
56 #define DOWN 8
57 #define VERTICAL (UP|DOWN)
59 /****** Global Variables ******/
60 extern Time LastTimestamp;
62 extern Cursor wCursor[WCUR_LAST];
64 extern WPreferences wPreferences;
66 extern Atom _XA_WM_PROTOCOLS;
73 void
74 wGetGeometryWindowSize(WScreen *scr, unsigned int *width,
75 unsigned int *height)
77 *width = WMWidthOfString(scr->info_text_font, "-8888 x -8888", 13);
79 *height = (6 * WMFontHeight(scr->info_text_font)) / 4 - 1;
85 *----------------------------------------------------------------------
86 * checkMouseSamplingRate-
87 * For lowering the mouse motion sampling rate for machines where
88 * it's too high (SGIs). If it returns False then the event should be
89 * ignored.
90 *----------------------------------------------------------------------
92 static Bool
93 checkMouseSamplingRate(XEvent *ev)
95 static Time previousMotion = 0;
97 if (ev->type == MotionNotify) {
98 if (ev->xmotion.time - previousMotion < DELAY_BETWEEN_MOUSE_SAMPLING) {
99 return False;
100 } else {
101 previousMotion = ev->xmotion.time;
104 return True;
110 *----------------------------------------------------------------------
111 * moveGeometryDisplayCentered
113 * routine that moves the geometry/position window on scr so it is
114 * centered over the given coordinates (x,y). Also the window position
115 * is clamped so it stays on the screen at all times.
116 *----------------------------------------------------------------------
118 static void
119 moveGeometryDisplayCentered(WScreen *scr, int x, int y)
121 x -= scr->geometry_display_width / 2;
122 y -= scr->geometry_display_height / 2;
124 if (x < 1)
125 x = 1;
126 else if (x > (scr->scr_width - scr->geometry_display_width - 3))
127 x = scr->scr_width - scr->geometry_display_width - 3;
129 if (y < 1)
130 y = 1;
131 else if (y > (scr->scr_height - scr->geometry_display_height - 3))
132 y = scr->scr_height - scr->geometry_display_height - 3;
134 XMoveWindow(dpy, scr->geometry_display, x, y);
138 static void
139 showPosition(WWindow *wwin, int x, int y)
141 WScreen *scr = wwin->screen_ptr;
142 GC gc = scr->info_text_gc;
143 char num[16];
144 int fw, fh;
146 if (wPreferences.move_display == WDIS_NEW) {
147 #if 1
148 int width = wwin->frame->core->width;
149 int height = wwin->frame->core->height;
151 GC lgc = scr->line_gc;
152 XSetForeground(dpy, lgc, scr->line_pixel);
153 sprintf(num, "%i", x);
155 XDrawLine(dpy, scr->root_win, lgc, 0, y-1, scr->scr_width, y-1);
156 XDrawLine(dpy, scr->root_win, lgc, 0, y+height+2, scr->scr_width,
157 y+height+2);
158 XDrawLine(dpy, scr->root_win, lgc, x-1, 0, x-1, scr->scr_height);
159 XDrawLine(dpy, scr->root_win, lgc, x+width+2, 0, x+width+2,
160 scr->scr_height);
161 #endif
162 } else {
163 XClearArea(dpy, scr->geometry_display, 1, 1,
164 scr->geometry_display_width-2, scr->geometry_display_height-2,
165 False);
166 sprintf(num, "%+i %-+i", x, y);
167 fw = WMWidthOfString(scr->info_text_font, num, strlen(num));
169 XSetForeground(dpy, gc, scr->black_pixel);
171 fh = WMFontHeight(scr->info_text_font);
172 WMDrawString(scr->wmscreen, scr->geometry_display, gc,
173 scr->info_text_font,
174 (scr->geometry_display_width - 2 - fw) / 2,
175 (scr->geometry_display_height-fh)/2, num, strlen(num));
176 wDrawBevel(scr->geometry_display, scr->geometry_display_width+1,
177 scr->geometry_display_height+1,
178 scr->widget_texture, WREL_RAISED);
183 static void
184 cyclePositionDisplay(WWindow *wwin, int x, int y, int w, int h)
186 WScreen *scr = wwin->screen_ptr;
188 wPreferences.move_display++;
189 wPreferences.move_display %= NUM_DISPLAYS;
191 if (wPreferences.move_display == WDIS_NEW) {
192 XUnmapWindow(dpy, scr->geometry_display);
193 } else {
194 if (wPreferences.move_display == WDIS_CENTER) {
195 moveGeometryDisplayCentered(scr,
196 scr->scr_width/2, scr->scr_height/2);
197 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
198 moveGeometryDisplayCentered(scr, 1, 1);
199 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
200 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
202 XMapRaised(dpy, scr->geometry_display);
207 static void
208 mapPositionDisplay(WWindow *wwin, int x, int y, int w, int h)
210 WScreen *scr = wwin->screen_ptr;
212 if (wPreferences.move_display == WDIS_NEW) {
213 return;
214 } else if (wPreferences.move_display == WDIS_CENTER) {
215 moveGeometryDisplayCentered(scr, scr->scr_width / 2,
216 scr->scr_height / 2);
217 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
218 moveGeometryDisplayCentered(scr, 1, 1);
219 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
220 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
222 XMapRaised(dpy, scr->geometry_display);
223 showPosition(wwin, x, y);
226 #define unmapPositionDisplay(w) \
227 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
230 static void
231 showGeometry(WWindow *wwin, int x1, int y1, int x2, int y2, int direction)
233 WScreen *scr = wwin->screen_ptr;
234 Window root = scr->root_win;
235 GC gc = scr->line_gc;
236 int ty, by, my, x, y, mx, s;
237 char num[16];
238 XSegment segment[4];
239 int fw, fh;
241 ty = y1 + wwin->frame->top_width;
242 by = y2 - wwin->frame->bottom_width;
243 fw = WMWidthOfString(scr->info_text_font, "8888", 4);
244 fh = WMFontHeight(scr->info_text_font);
246 if (wPreferences.size_display == WDIS_NEW) {
247 XSetForeground(dpy, gc, scr->line_pixel);
249 /* vertical geometry */
250 if (((direction & LEFT) && (x2 < scr->scr_width - fw)) || (x1 < fw)) {
251 x = x2;
252 s = -15;
253 } else {
254 x = x1;
255 s = 15;
257 my = (ty + by) / 2;
259 /* top arrow */
260 /* end bar */
261 segment[0].x1 = x - (s + 6); segment[0].y1 = ty;
262 segment[0].x2 = x - (s - 10); segment[0].y2 = ty;
264 /* arrowhead */
265 segment[1].x1 = x - (s - 2); segment[1].y1 = ty + 1;
266 segment[1].x2 = x - (s - 5); segment[1].y2 = ty + 7;
268 segment[2].x1 = x - (s - 2); segment[2].y1 = ty + 1;
269 segment[2].x2 = x - (s + 1); segment[2].y2 = ty + 7;
271 /* line */
272 segment[3].x1 = x - (s - 2); segment[3].y1 = ty + 1;
273 segment[3].x2 = x - (s - 2); segment[3].y2 = my - fh/2 - 1;
275 XDrawSegments(dpy, root, gc, segment, 4);
277 /* bottom arrow */
278 /* end bar */
279 segment[0].y1 = by;
280 segment[0].y2 = by;
282 /* arrowhead */
283 segment[1].y1 = by - 1;
284 segment[1].y2 = by - 7;
286 segment[2].y1 = by - 1;
287 segment[2].y2 = by - 7;
289 /* line */
290 segment[3].y1 = my + fh/2 + 2;
291 segment[3].y2 = by - 1;
293 XDrawSegments(dpy, root, gc, segment, 4);
295 sprintf(num, "%i", (by - ty - wwin->normal_hints->base_height) /
296 wwin->normal_hints->height_inc);
297 fw = WMWidthOfString(scr->info_text_font, num, strlen(num));
299 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
301 /* Display the height. */
302 WMDrawString(scr->wmscreen, root, gc, scr->info_text_font,
303 x - s + 3 - fw/2, my - fh/2 + 1, num, strlen(num));
304 XSetForeground(dpy, gc, scr->line_pixel);
305 /* horizontal geometry */
306 if (y1 < 15) {
307 y = y2;
308 s = -15;
309 } else {
310 y = y1;
311 s = 15;
313 mx = x1 + (x2 - x1)/2;
314 sprintf(num, "%i", (x2 - x1 - wwin->normal_hints->base_width) /
315 wwin->normal_hints->width_inc);
316 fw = WMWidthOfString(scr->info_text_font, num, strlen(num));
318 /* left arrow */
319 /* end bar */
320 segment[0].x1 = x1; segment[0].y1 = y - (s + 6);
321 segment[0].x2 = x1; segment[0].y2 = y - (s - 10);
323 /* arrowhead */
324 segment[1].x1 = x1 + 7; segment[1].y1 = y - (s + 1);
325 segment[1].x2 = x1 + 1; segment[1].y2 = y - (s - 2);
327 segment[2].x1 = x1 + 1; segment[2].y1 = y - (s - 2);
328 segment[2].x2 = x1 + 7; segment[2].y2 = y - (s - 5);
330 /* line */
331 segment[3].x1 = x1 + 1; segment[3].y1 = y - (s - 2);
332 segment[3].x2 = mx - fw/2 - 2; segment[3].y2 = y - (s - 2);
334 XDrawSegments(dpy, root, gc, segment, 4);
336 /* right arrow */
337 /* end bar */
338 segment[0].x1 = x2 + 1;
339 segment[0].x2 = x2 + 1;
341 /* arrowhead */
342 segment[1].x1 = x2 - 6;
343 segment[1].x2 = x2;
345 segment[2].x1 = x2;
346 segment[2].x2 = x2 - 6;
348 /* line */
349 segment[3].x1 = mx + fw/2 + 2;
350 segment[3].x2 = x2;
352 XDrawSegments(dpy, root, gc, segment, 4);
354 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
356 /* Display the width. */
357 WMDrawString(scr->wmscreen, root, gc, scr->info_text_font,
358 mx - fw/2 + 1, y - s - fh/2 + 1, num, strlen(num));
359 } else {
360 XClearArea(dpy, scr->geometry_display, 1, 1,
361 scr->geometry_display_width-2, scr->geometry_display_height-2,
362 False);
363 sprintf(num, "%i x %-i", (x2 - x1 - wwin->normal_hints->base_width)
364 / wwin->normal_hints->width_inc,
365 (by - ty - wwin->normal_hints->base_height)
366 / wwin->normal_hints->height_inc);
367 fw = WMWidthOfString(scr->info_text_font, num, strlen(num));
369 XSetForeground(dpy, scr->info_text_gc, scr->black_pixel);
371 /* Display the height. */
372 WMDrawString(scr->wmscreen, scr->geometry_display, scr->info_text_gc,
373 scr->info_text_font,
374 (scr->geometry_display_width-fw)/2,
375 (scr->geometry_display_height-fh)/2, num, strlen(num));
376 wDrawBevel(scr->geometry_display, scr->geometry_display_width+1,
377 scr->geometry_display_height+1,
378 scr->widget_texture, WREL_RAISED);
383 static void
384 cycleGeometryDisplay(WWindow *wwin, int x, int y, int w, int h, int dir)
386 WScreen *scr = wwin->screen_ptr;
388 wPreferences.size_display++;
389 wPreferences.size_display %= NUM_DISPLAYS;
391 if (wPreferences.size_display == WDIS_NEW) {
392 XUnmapWindow(dpy, scr->geometry_display);
393 } else {
394 if (wPreferences.size_display == WDIS_CENTER) {
395 moveGeometryDisplayCentered(scr,
396 scr->scr_width / 2, scr->scr_height / 2);
397 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
398 moveGeometryDisplayCentered(scr, 1, 1);
399 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
400 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
402 XMapRaised(dpy, scr->geometry_display);
403 showGeometry(wwin, x, y, x + w, y + h, dir);
408 static void
409 mapGeometryDisplay(WWindow *wwin, int x, int y, int w, int h)
411 WScreen *scr = wwin->screen_ptr;
413 if (wPreferences.size_display == WDIS_NEW)
414 return;
416 if (wPreferences.size_display == WDIS_CENTER) {
417 moveGeometryDisplayCentered(scr, scr->scr_width / 2,
418 scr->scr_height / 2);
419 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
420 moveGeometryDisplayCentered(scr, 1, 1);
421 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
422 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
424 XMapRaised(dpy, scr->geometry_display);
425 showGeometry(wwin, x, y, x + w, y + h, 0);
428 #define unmapGeometryDisplay(w) \
429 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
432 static void
433 doWindowMove(WWindow *wwin, WMBag *bag, int dx, int dy)
435 WWindow *tmpw;
436 int x, y;
437 int scr_width = wwin->screen_ptr->scr_width;
438 int scr_height = wwin->screen_ptr->scr_height;
440 if (!bag || !WMGetBagItemCount(bag)) {
441 wWindowMove(wwin, wwin->frame_x + dx, wwin->frame_y + dy);
442 } else {
443 int i;
444 for (i = 0; i < WMGetBagItemCount(bag); i++) {
445 tmpw = WMGetFromBag(bag, i);
446 x = tmpw->frame_x + dx;
447 y = tmpw->frame_y + dy;
449 /* don't let windows become unreachable */
451 if (x + (int)tmpw->frame->core->width < 20)
452 x = 20 - (int)tmpw->frame->core->width;
453 else if (x + 20 > scr_width)
454 x = scr_width - 20;
456 if (y + (int)tmpw->frame->core->height < 20)
457 y = 20 - (int)tmpw->frame->core->height;
458 else if (y + 20 > scr_height)
459 y = scr_height - 20;
461 wWindowMove(tmpw, x, y);
467 static void
468 drawTransparentFrame(WWindow *wwin, int x, int y, int width, int height)
470 Window root = wwin->screen_ptr->root_win;
471 GC gc = wwin->screen_ptr->frame_gc;
472 int h = 0;
473 int bottom = 0;
475 if (!WFLAGP(wwin, no_titlebar) && !wwin->flags.shaded) {
476 h = WMFontHeight(wwin->screen_ptr->title_font) + TITLEBAR_EXTRA_HEIGHT;
478 if (!WFLAGP(wwin, no_resizebar) && !wwin->flags.shaded) {
479 /* Can't use wwin-frame->bottom_width because, in some cases
480 (e.g. interactive placement), frame does not point to anything. */
481 bottom = RESIZEBAR_HEIGHT - 1;
483 XDrawRectangle(dpy, root, gc, x, y, width + 1, height + 1);
485 if (h > 0) {
486 XDrawLine(dpy, root, gc, x + 1, y + h, x + width + 1, y + h);
488 if (bottom > 0) {
489 XDrawLine(dpy, root, gc, x + 1,
490 y + height - bottom,
491 x + width + 1,
492 y + height - bottom);
497 static void
498 drawFrames(WWindow *wwin, WMBag *bag, int dx, int dy)
500 WWindow *tmpw;
501 int scr_width = wwin->screen_ptr->scr_width;
502 int scr_height = wwin->screen_ptr->scr_height;
503 int x, y;
505 if (!bag) {
507 x = wwin->frame_x + dx;
508 y = wwin->frame_y + dy;
510 drawTransparentFrame(wwin, x, y,
511 wwin->frame->core->width,
512 wwin->frame->core->height);
514 } else {
515 int i;
516 for (i = 0; i < WMGetBagItemCount(bag); i++) {
517 tmpw = WMGetFromBag(bag, i);
518 x = tmpw->frame_x + dx;
519 y = tmpw->frame_y + dy;
521 /* don't let windows become unreachable */
523 if (x + (int)tmpw->frame->core->width < 20)
524 x = 20 - (int)tmpw->frame->core->width;
525 else if (x + 20 > scr_width)
526 x = scr_width - 20;
528 if (y + (int)tmpw->frame->core->height < 20)
529 y = 20 - (int)tmpw->frame->core->height;
530 else if (y + 20 > scr_height)
531 y = scr_height - 20;
533 drawTransparentFrame(tmpw, x, y, tmpw->frame->core->width,
534 tmpw->frame->core->height);
541 static void
542 flushMotion()
544 XEvent ev;
546 XSync(dpy, False);
547 while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
551 static void
552 crossWorkspace(WScreen *scr, WWindow *wwin, int opaque_move,
553 int new_workspace, int rewind)
555 /* do not let window be unmapped */
556 if (opaque_move) {
557 wwin->flags.changing_workspace = 1;
558 wWindowChangeWorkspace(wwin, new_workspace);
560 /* go to new workspace */
561 wWorkspaceChange(scr, new_workspace);
563 wwin->flags.changing_workspace = 0;
565 if (rewind)
566 XWarpPointer(dpy, None, None, 0, 0, 0, 0, scr->scr_width - 20, 0);
567 else
568 XWarpPointer(dpy, None, None, 0, 0, 0, 0, -(scr->scr_width - 20), 0);
570 flushMotion();
572 if (!opaque_move) {
573 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
574 |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
575 GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
582 typedef struct {
583 /* arrays of WWindows sorted by the respective border position */
584 WWindow **topList; /* top border */
585 WWindow **leftList; /* left border */
586 WWindow **rightList; /* right border */
587 WWindow **bottomList; /* bottom border */
588 int count;
590 /* index of window in the above lists indicating the relative position
591 * of the window with the others */
592 int topIndex;
593 int leftIndex;
594 int rightIndex;
595 int bottomIndex;
597 int rubCount; /* for workspace switching */
599 int winWidth, winHeight; /* width/height of the window */
600 int realX, realY; /* actual position of the window */
601 int calcX, calcY; /* calculated position of window */
602 int omouseX, omouseY; /* old mouse position */
603 int mouseX, mouseY; /* last known position of the pointer */
604 } MoveData;
606 #define WTOP(w) (w)->frame_y
607 #define WLEFT(w) (w)->frame_x
608 #define WRIGHT(w) ((w)->frame_x + (int)(w)->frame->core->width + FRAME_BORDER_WIDTH)
609 #define WBOTTOM(w) ((w)->frame_y + (int)(w)->frame->core->height + FRAME_BORDER_WIDTH)
611 static int
612 compareWTop(const void *a, const void *b)
614 WWindow *wwin1 = *(WWindow**)a;
615 WWindow *wwin2 = *(WWindow**)b;
617 if (WTOP(wwin1) > WTOP(wwin2))
618 return -1;
619 else if (WTOP(wwin1) < WTOP(wwin2))
620 return 1;
621 else
622 return 0;
626 static int
627 compareWLeft(const void *a, const void *b)
629 WWindow *wwin1 = *(WWindow**)a;
630 WWindow *wwin2 = *(WWindow**)b;
632 if (WLEFT(wwin1) > WLEFT(wwin2))
633 return -1;
634 else if (WLEFT(wwin1) < WLEFT(wwin2))
635 return 1;
636 else
637 return 0;
641 static int
642 compareWRight(const void *a, const void *b)
644 WWindow *wwin1 = *(WWindow**)a;
645 WWindow *wwin2 = *(WWindow**)b;
647 if (WRIGHT(wwin1) < WRIGHT(wwin2))
648 return -1;
649 else if (WRIGHT(wwin1) > WRIGHT(wwin2))
650 return 1;
651 else
652 return 0;
657 static int
658 compareWBottom(const void *a, const void *b)
660 WWindow *wwin1 = *(WWindow**)a;
661 WWindow *wwin2 = *(WWindow**)b;
663 if (WBOTTOM(wwin1) < WBOTTOM(wwin2))
664 return -1;
665 else if (WBOTTOM(wwin1) > WBOTTOM(wwin2))
666 return 1;
667 else
668 return 0;
672 static void
673 updateResistance(WWindow *wwin, MoveData *data, int newX, int newY)
675 int i;
676 int newX2 = newX + data->winWidth;
677 int newY2 = newY + data->winHeight;
678 Bool ok = False;
680 if (newX < data->realX) {
681 if (data->rightIndex > 0
682 && newX < WRIGHT(data->rightList[data->rightIndex-1])) {
683 ok = True;
684 } else if (data->leftIndex <= data->count-1
685 && newX2 <= WLEFT(data->leftList[data->leftIndex])) {
686 ok = True;
688 } else if (newX > data->realX) {
689 if (data->leftIndex > 0
690 && newX2 > WLEFT(data->leftList[data->leftIndex-1])) {
691 ok = True;
692 } else if (data->rightIndex <= data->count-1
693 && newX >= WRIGHT(data->rightList[data->rightIndex])) {
694 ok = True;
698 if (!ok) {
699 if (newY < data->realY) {
700 if (data->bottomIndex > 0
701 && newY < WBOTTOM(data->bottomList[data->bottomIndex-1])) {
702 ok = True;
703 } else if (data->topIndex <= data->count-1
704 && newY2 <= WTOP(data->topList[data->topIndex])) {
705 ok = True;
707 } else if (newY > data->realY) {
708 if (data->topIndex > 0
709 && newY2 > WTOP(data->topList[data->topIndex-1])) {
710 ok = True;
711 } else if (data->bottomIndex <= data->count-1
712 && newY >= WBOTTOM(data->bottomList[data->bottomIndex])) {
713 ok = True;
718 if (!ok)
719 return;
721 /* TODO: optimize this */
722 if (data->realY < WBOTTOM(data->bottomList[0])) {
723 data->bottomIndex = 0;
725 if (data->realX < WRIGHT(data->rightList[0])) {
726 data->rightIndex = 0;
728 if ((data->realX + data->winWidth) > WLEFT(data->leftList[0])) {
729 data->leftIndex = 0;
731 if ((data->realY + data->winHeight) > WTOP(data->topList[0])) {
732 data->topIndex = 0;
734 for (i = 0; i < data->count; i++) {
735 if (data->realY > WBOTTOM(data->bottomList[i])) {
736 data->bottomIndex = i + 1;
738 if (data->realX > WRIGHT(data->rightList[i])) {
739 data->rightIndex = i + 1;
741 if ((data->realX + data->winWidth) < WLEFT(data->leftList[i])) {
742 data->leftIndex = i + 1;
744 if ((data->realY + data->winHeight) < WTOP(data->topList[i])) {
745 data->topIndex = i + 1;
751 static void
752 freeMoveData(MoveData *data)
754 if (data->topList)
755 free(data->topList);
756 if (data->leftList)
757 free(data->leftList);
758 if (data->rightList)
759 free(data->rightList);
760 if (data->bottomList)
761 free(data->bottomList);
765 static void
766 updateMoveData(WWindow *wwin, MoveData *data)
768 WScreen *scr = wwin->screen_ptr;
769 WWindow *tmp;
770 int i;
772 data->count = 0;
773 tmp = scr->focused_window;
774 while (tmp) {
775 if (tmp != wwin && scr->current_workspace == tmp->frame->workspace
776 && !tmp->flags.miniaturized
777 && !tmp->flags.hidden
778 && !tmp->flags.obscured
779 && !WFLAGP(tmp, sunken)) {
780 data->topList[data->count] = tmp;
781 data->leftList[data->count] = tmp;
782 data->rightList[data->count] = tmp;
783 data->bottomList[data->count] = tmp;
784 data->count++;
786 tmp = tmp->prev;
789 if (data->count == 0) {
790 data->topIndex = 0;
791 data->leftIndex = 0;
792 data->rightIndex = 0;
793 data->bottomIndex = 0;
794 return;
798 * order from closest to the border of the screen to farthest
800 qsort(data->topList, data->count, sizeof(WWindow**), compareWTop);
801 qsort(data->leftList, data->count, sizeof(WWindow**), compareWLeft);
802 qsort(data->rightList, data->count, sizeof(WWindow**), compareWRight);
803 qsort(data->bottomList, data->count, sizeof(WWindow**), compareWBottom);
805 /* figure the position of the window relative to the others */
807 data->topIndex = -1;
808 data->leftIndex = -1;
809 data->rightIndex = -1;
810 data->bottomIndex = -1;
812 if (WTOP(wwin) < WBOTTOM(data->bottomList[0])) {
813 data->bottomIndex = 0;
815 if (WLEFT(wwin) < WRIGHT(data->rightList[0])) {
816 data->rightIndex = 0;
818 if (WRIGHT(wwin) > WLEFT(data->leftList[0])) {
819 data->leftIndex = 0;
821 if (WBOTTOM(wwin) > WTOP(data->topList[0])) {
822 data->topIndex = 0;
824 for (i = 0; i < data->count; i++) {
825 if (WTOP(wwin) >= WBOTTOM(data->bottomList[i])) {
826 data->bottomIndex = i + 1;
828 if (WLEFT(wwin) >= WRIGHT(data->rightList[i])) {
829 data->rightIndex = i + 1;
831 if (WRIGHT(wwin) <= WLEFT(data->leftList[i])) {
832 data->leftIndex = i + 1;
834 if (WBOTTOM(wwin) <= WTOP(data->topList[i])) {
835 data->topIndex = i + 1;
841 static void
842 initMoveData(WWindow *wwin, MoveData *data)
844 int i;
845 WWindow *tmp;
847 memset(data, 0, sizeof(MoveData));
849 for (i = 0, tmp = wwin->screen_ptr->focused_window;
850 tmp != NULL;
851 tmp = tmp->prev, i++);
853 if (i > 1) {
854 data->topList = wmalloc(sizeof(WWindow*) * i);
855 data->leftList = wmalloc(sizeof(WWindow*) * i);
856 data->rightList = wmalloc(sizeof(WWindow*) * i);
857 data->bottomList = wmalloc(sizeof(WWindow*) * i);
859 updateMoveData(wwin, data);
862 data->realX = wwin->frame_x;
863 data->realY = wwin->frame_y;
864 data->calcX = wwin->frame_x;
865 data->calcY = wwin->frame_y;
867 data->winWidth = wwin->frame->core->width + 2;
868 data->winHeight = wwin->frame->core->height + 2;
872 static Bool
873 checkWorkspaceChange(WWindow *wwin, MoveData *data, Bool opaqueMove)
875 WScreen *scr = wwin->screen_ptr;
876 Bool changed = False;
878 if (data->mouseX <= 1) {
879 if (scr->current_workspace > 0) {
881 crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace - 1,
882 True);
883 changed = True;
884 data->rubCount = 0;
886 } else if (scr->current_workspace == 0 && wPreferences.ws_cycle) {
888 crossWorkspace(scr, wwin, opaqueMove, scr->workspace_count - 1,
889 True);
890 changed = True;
891 data->rubCount = 0;
893 } else if (data->mouseX >= scr->scr_width - 2) {
895 if (scr->current_workspace == scr->workspace_count - 1) {
897 if (wPreferences.ws_cycle
898 || scr->workspace_count == MAX_WORKSPACES) {
900 crossWorkspace(scr, wwin, opaqueMove, 0, False);
901 changed = True;
902 data->rubCount = 0;
904 /* if user insists on trying to go to next workspace even when
905 * it's already the last, create a new one */
906 else if (data->omouseX == data->mouseX
907 && wPreferences.ws_advance) {
909 /* detect user "rubbing" the window against the edge */
910 if (data->rubCount > 0
911 && data->omouseY - data->mouseY > MOVE_THRESHOLD) {
913 data->rubCount = -(data->rubCount + 1);
915 } else if (data->rubCount <= 0
916 && data->mouseY - data->omouseY > MOVE_THRESHOLD) {
918 data->rubCount = -data->rubCount + 1;
921 /* create a new workspace */
922 if (abs(data->rubCount) > 2) {
923 /* go to next workspace */
924 wWorkspaceNew(scr);
926 crossWorkspace(scr, wwin, opaqueMove,
927 scr->current_workspace+1, False);
928 changed = True;
929 data->rubCount = 0;
931 } else if (scr->current_workspace < scr->workspace_count) {
933 /* go to next workspace */
934 crossWorkspace(scr, wwin, opaqueMove,
935 scr->current_workspace+1, False);
936 changed = True;
937 data->rubCount = 0;
939 } else {
940 data->rubCount = 0;
943 return changed;
947 static void
948 updateWindowPosition(WWindow *wwin, MoveData *data, Bool doResistance,
949 Bool opaqueMove, int newMouseX, int newMouseY)
951 WScreen *scr = wwin->screen_ptr;
952 int dx, dy; /* how much mouse moved */
953 int winL, winR, winT, winB; /* requested new window position */
954 int newX, newY; /* actual new window position */
955 Bool hresist, vresist;
956 Bool updateIndex;
957 Bool attract;
959 hresist = False;
960 vresist = False;
962 updateIndex = False;
964 /* check the direction of the movement */
965 dx = newMouseX - data->mouseX;
966 dy = newMouseY - data->mouseY;
968 data->omouseX = data->mouseX;
969 data->omouseY = data->mouseY;
970 data->mouseX = newMouseX;
971 data->mouseY = newMouseY;
973 winL = data->calcX + dx;
974 winR = data->calcX + data->winWidth + dx;
975 winT = data->calcY + dy;
976 winB = data->calcY + data->winHeight + dy;
978 newX = data->realX;
979 newY = data->realY;
981 if (doResistance) {
982 int l_edge, r_edge;
983 int edge_l, edge_r;
984 int t_edge, b_edge;
985 int edge_t, edge_b;
986 int resist;
988 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
989 attract = wPreferences.attract;
990 /* horizontal movement: check horizontal edge resistances */
991 if (dx || dy) {
992 int i;
993 /* window is the leftmost window: check against screen edge */
994 l_edge = scr->totalUsableArea.x1;
995 r_edge = scr->totalUsableArea.x2 + resist;
996 edge_l = scr->totalUsableArea.x1 - resist;
997 edge_r = scr->totalUsableArea.x2;
999 /* 1 */
1000 if ((data->rightIndex >= 0) && (data->rightIndex <= data->count)) {
1001 WWindow *looprw;
1003 for (i = data->rightIndex - 1; i >= 0; i--) {
1004 looprw = data->rightList[i];
1005 if (!(data->realY > WBOTTOM(looprw)
1006 || (data->realY + data->winHeight) < WTOP(looprw))) {
1007 if (attract
1008 || ((data->realX < (WRIGHT(looprw) + 2)) && dx < 0)) {
1009 l_edge = WRIGHT(looprw) + 1;
1010 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1012 break;
1016 if (attract) {
1017 for (i = data->rightIndex; i < data->count; i++) {
1018 looprw = data->rightList[i];
1019 if(!(data->realY > WBOTTOM(looprw)
1020 || (data->realY + data->winHeight) < WTOP(looprw))) {
1021 r_edge = WRIGHT(looprw) + 1;
1022 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1023 break;
1029 if ((data->leftIndex >= 0) && (data->leftIndex <= data->count)) {
1030 WWindow *looprw;
1032 for (i = data->leftIndex - 1; i >= 0; i--) {
1033 looprw = data->leftList[i];
1034 if (!(data->realY > WBOTTOM(looprw)
1035 || (data->realY + data->winHeight) < WTOP(looprw))) {
1036 if (attract
1037 || (((data->realX + data->winWidth) > (WLEFT(looprw) - 1)) && dx > 0)) {
1038 edge_r = WLEFT(looprw);
1039 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1041 break;
1045 if (attract)
1046 for (i = data->leftIndex; i < data->count; i++) {
1047 looprw = data->leftList[i];
1048 if(!(data->realY > WBOTTOM(looprw)
1049 || (data->realY + data->winHeight) < WTOP(looprw))) {
1050 edge_l = WLEFT(looprw);
1051 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1052 break;
1058 printf("%d %d\n",winL,winR);
1059 printf("l_ %d r_ %d _l %d _r %d\n",l_edge,r_edge,edge_l,edge_r);
1062 if ((winL - l_edge) < (r_edge - winL)) {
1063 if (resist > 0) {
1064 if ((attract && winL <= l_edge + resist && winL >= l_edge - resist)
1065 || (dx < 0 && winL <= l_edge && winL >= l_edge - resist)) {
1066 newX = l_edge;
1067 hresist = True;
1070 } else {
1071 if (resist > 0 && attract && winL >= r_edge - resist && winL <= r_edge + resist) {
1072 newX = r_edge;
1073 hresist = True;
1077 if ((winR - edge_l) < (edge_r - winR)) {
1078 if (resist > 0 && attract && winR <= edge_l + resist && winR >= edge_l - resist) {
1079 newX = edge_l - data->winWidth;
1080 hresist = True;
1082 } else {
1083 if (resist > 0) {
1084 if ((attract && winR >= edge_r - resist && winR <= edge_r + resist)
1085 || (dx > 0 && winR >= edge_r && winR <= edge_r + resist)) {
1086 newX = edge_r - data->winWidth;
1087 hresist = True;
1092 /* VeRT */
1093 t_edge = scr->totalUsableArea.y1;
1094 b_edge = scr->totalUsableArea.y2 + resist;
1095 edge_t = scr->totalUsableArea.y1 - resist;
1096 edge_b = scr->totalUsableArea.y2;
1098 if ((data->bottomIndex >= 0) && (data->bottomIndex <= data->count)) {
1099 WWindow *looprw;
1101 for (i = data->bottomIndex - 1; i >= 0; i--) {
1102 looprw = data->bottomList[i];
1103 if (!(data->realX > WRIGHT(looprw)
1104 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1105 if (attract
1106 || ((data->realY < (WBOTTOM(looprw) + 2)) && dy < 0)) {
1107 t_edge = WBOTTOM(looprw) + 1;
1108 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1110 break;
1114 if (attract) {
1115 for (i = data->bottomIndex; i < data->count; i++) {
1116 looprw = data->bottomList[i];
1117 if(!(data->realX > WRIGHT(looprw)
1118 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1119 b_edge = WBOTTOM(looprw) + 1;
1120 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1121 break;
1127 if ((data->topIndex >= 0) && (data->topIndex <= data->count)) {
1128 WWindow *looprw;
1130 for (i = data->topIndex - 1; i >= 0; i--) {
1131 looprw = data->topList[i];
1132 if (!(data->realX > WRIGHT(looprw)
1133 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1134 if (attract
1135 || (((data->realY + data->winHeight) > (WTOP(looprw) - 1)) && dy > 0)) {
1136 edge_b = WTOP(looprw);
1137 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1139 break;
1143 if (attract)
1144 for (i = data->topIndex; i < data->count; i++) {
1145 looprw = data->topList[i];
1146 if(!(data->realX > WRIGHT(looprw)
1147 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1148 edge_t = WTOP(looprw);
1149 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1150 break;
1155 if ((winT - t_edge) < (b_edge - winT)) {
1156 if (resist > 0) {
1157 if ((attract && winT <= t_edge + resist && winT >= t_edge - resist)
1158 || (dy < 0 && winT <= t_edge && winT >= t_edge - resist)) {
1159 newY = t_edge;
1160 vresist = True;
1164 else {
1165 if (resist > 0 && attract && winT >= b_edge - resist && winT <= b_edge + resist) {
1166 newY = b_edge;
1167 vresist = True;
1171 if ((winB - edge_t) < (edge_b - winB)) {
1172 if (resist > 0 && attract && winB <= edge_t + resist && winB >= edge_t - resist) {
1173 newY = edge_t - data->winHeight;
1174 vresist = True;
1177 else {
1178 if (resist > 0) {
1179 if ((attract && winB >= edge_b - resist && winB <= edge_b + resist)
1180 || (dy > 0 && winB >= edge_b && winB <= edge_b + resist)) {
1181 newY = edge_b - data->winHeight;
1182 vresist = True;
1187 /* END VeRT */
1191 /* update window position */
1192 data->calcX += dx;
1193 data->calcY += dy;
1195 if (((dx > 0 && data->calcX - data->realX > 0)
1196 || (dx < 0 && data->calcX - data->realX < 0)) && !hresist)
1197 newX = data->calcX;
1199 if (((dy > 0 && data->calcY - data->realY > 0)
1200 || (dy < 0 && data->calcY - data->realY < 0)) && !vresist)
1201 newY = data->calcY;
1203 if (data->realX != newX || data->realY != newY) {
1205 if (wPreferences.move_display == WDIS_NEW
1206 && !scr->selected_windows) {
1207 showPosition(wwin, data->realX, data->realY);
1209 if (opaqueMove) {
1210 doWindowMove(wwin, scr->selected_windows,
1211 newX - wwin->frame_x,
1212 newY - wwin->frame_y);
1213 } else {
1214 /* erase frames */
1215 drawFrames(wwin, scr->selected_windows,
1216 data->realX - wwin->frame_x,
1217 data->realY - wwin->frame_y);
1220 if (!scr->selected_windows
1221 && wPreferences.move_display == WDIS_FRAME_CENTER) {
1223 moveGeometryDisplayCentered(scr, newX + data->winWidth/2,
1224 newY + data->winHeight/2);
1227 if (!opaqueMove) {
1228 /* draw frames */
1229 drawFrames(wwin, scr->selected_windows,
1230 newX - wwin->frame_x,
1231 newY - wwin->frame_y);
1234 if (!scr->selected_windows) {
1235 showPosition(wwin, newX, newY);
1240 /* recalc relative window position */
1241 if (doResistance && (data->realX != newX || data->realY != newY)) {
1242 updateResistance(wwin, data, newX, newY);
1245 data->realX = newX;
1246 data->realY = newY;
1250 #define _KS KEY_CONTROL_WINDOW_WEIGHT
1253 wKeyboardMoveResizeWindow(WWindow *wwin)
1255 WScreen *scr = wwin->screen_ptr;
1256 Window root = scr->root_win;
1257 XEvent event;
1258 int w = wwin->frame->core->width;
1259 int h = wwin->frame->core->height;
1260 int scr_width = wwin->screen_ptr->scr_width;
1261 int scr_height = wwin->screen_ptr->scr_height;
1262 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1263 int src_x = wwin->frame_x;
1264 int src_y = wwin->frame_y;
1265 int done,off_x,off_y,ww,wh;
1266 int kspeed = _KS;
1267 Time lastTime = 0;
1268 KeySym keysym=NoSymbol;
1269 int moment=0;
1270 KeyCode shiftl,shiftr,ctrll,ctrlmode;
1272 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1273 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1274 ctrll = XKeysymToKeycode(dpy, XK_Control_L);
1275 ctrlmode=done=off_x=off_y=0;
1277 XSync(dpy, False);
1278 wusleep(10000);
1279 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1281 if (!wwin->flags.selected) {
1282 wUnselectWindows(scr);
1284 XGrabServer(dpy);
1285 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
1286 |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
1287 GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime);
1289 if (wwin->flags.shaded || scr->selected_windows) {
1290 if(scr->selected_windows)
1291 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1292 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1293 if(!scr->selected_windows)
1294 mapPositionDisplay(wwin, src_x, src_y, w, h);
1295 } else {
1296 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1298 ww=w;
1299 wh=h;
1300 while(1) {
1302 looper.ox=off_x;
1303 looper.oy=off_y;
1305 WMMaskEvent(dpy, KeyPressMask | ButtonReleaseMask
1306 | ButtonPressMask | ExposureMask, &event);
1307 if (wwin->flags.shaded || scr->selected_windows) {
1308 if(scr->selected_windows)
1309 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1310 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1311 /*** I HATE EDGE RESISTANCE - ]d ***/
1313 else {
1314 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
1317 if(ctrlmode)
1318 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
1320 XUngrabServer(dpy);
1321 XSync(dpy, False);
1323 switch (event.type) {
1324 case KeyPress:
1325 /* accelerate */
1326 if (event.xkey.time - lastTime > 50) {
1327 kspeed/=(1 + (event.xkey.time - lastTime)/100);
1328 } else {
1329 if (kspeed < 20) {
1330 kspeed++;
1333 if (kspeed < _KS) kspeed = _KS;
1334 lastTime = event.xkey.time;
1336 if (event.xkey.state & ControlMask && !wwin->flags.shaded) {
1337 ctrlmode=1;
1338 wUnselectWindows(scr);
1340 else {
1341 ctrlmode=0;
1343 if (event.xkey.keycode == shiftl || event.xkey.keycode == shiftr) {
1344 if (ctrlmode)
1345 cycleGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh, 0);
1346 else
1347 cyclePositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
1349 else {
1351 keysym = XLookupKeysym(&event.xkey, 0);
1352 switch (keysym) {
1353 case XK_Return:
1354 done=2;
1355 break;
1356 case XK_Escape:
1357 done=1;
1358 break;
1359 case XK_Up:
1360 case XK_KP_Up:
1361 case XK_k:
1362 if (ctrlmode){
1363 if (moment != UP)
1364 h = wh;
1365 h-=kspeed;
1366 moment = UP;
1367 if (h < 1) h = 1;
1369 else off_y-=kspeed;
1370 break;
1371 case XK_Down:
1372 case XK_KP_Down:
1373 case XK_j:
1374 if (ctrlmode){
1375 if (moment != DOWN)
1376 h = wh;
1377 h+=kspeed;
1378 moment = DOWN;
1380 else off_y+=kspeed;
1381 break;
1382 case XK_Left:
1383 case XK_KP_Left:
1384 case XK_h:
1385 if (ctrlmode) {
1386 if (moment != LEFT)
1387 w = ww;
1388 w-=kspeed;
1389 if (w < 1) w = 1;
1390 moment = LEFT;
1392 else off_x-=kspeed;
1393 break;
1394 case XK_Right:
1395 case XK_KP_Right:
1396 case XK_l:
1397 if (ctrlmode) {
1398 if (moment != RIGHT)
1399 w = ww;
1400 w+=kspeed;
1401 moment = RIGHT;
1403 else off_x+=kspeed;
1404 break;
1407 ww=w;wh=h;
1408 wh-=vert_border;
1409 wWindowConstrainSize(wwin, &ww, &wh);
1410 wh+=vert_border;
1412 if (wPreferences.ws_cycle){
1413 if (src_x + off_x + ww < 20){
1414 if(!scr->current_workspace) {
1415 wWorkspaceChange(scr, scr->workspace_count-1);
1417 else wWorkspaceChange(scr, scr->current_workspace-1);
1418 off_x += scr_width;
1420 else if (src_x + off_x + 20 > scr_width){
1421 if(scr->current_workspace == scr->workspace_count-1) {
1422 wWorkspaceChange(scr, 0);
1424 else wWorkspaceChange(scr, scr->current_workspace+1);
1425 off_x -= scr_width;
1428 else {
1429 if (src_x + off_x + ww < 20)
1430 off_x = 20 - ww - src_x;
1431 else if (src_x + off_x + 20 > scr_width)
1432 off_x = scr_width - 20 - src_x;
1435 if (src_y + off_y + wh < 20) {
1436 off_y = 20 - wh - src_y;
1438 else if (src_y + off_y + 20 > scr_height) {
1439 off_y = scr_height - 20 - src_y;
1442 break;
1443 case ButtonPress:
1444 case ButtonRelease:
1445 done=1;
1446 break;
1447 default:
1448 WMHandleEvent(&event);
1449 break;
1452 XGrabServer(dpy);
1453 /*xxx*/
1455 if (wwin->flags.shaded && !scr->selected_windows){
1456 moveGeometryDisplayCentered(scr, src_x+off_x + w/2, src_y+off_y + h/2);
1458 else {
1459 if(ctrlmode){
1460 unmapPositionDisplay(wwin);
1461 mapGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
1463 else if(!scr->selected_windows){
1464 unmapGeometryDisplay(wwin);
1465 mapPositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
1469 if (wwin->flags.shaded || scr->selected_windows) {
1470 if(scr->selected_windows)
1471 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1472 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1474 else {
1475 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
1479 if(ctrlmode){
1480 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
1482 else if(!scr->selected_windows)
1483 showPosition(wwin, src_x+off_x, src_y+off_y);
1484 /**/
1486 if(done){
1487 scr->keymove_tick=0;
1489 WMDeleteTimerWithClientData(&looper);
1491 if (wwin->flags.shaded || scr->selected_windows) {
1492 if(scr->selected_windows)
1493 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1494 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1496 else {
1497 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
1500 if(ctrlmode){
1501 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
1502 unmapGeometryDisplay(wwin);
1504 else
1505 unmapPositionDisplay(wwin);
1506 XUngrabKeyboard(dpy, CurrentTime);
1507 XUngrabPointer(dpy, CurrentTime);
1508 XUngrabServer(dpy);
1510 if(done==2) {
1511 if (wwin->flags.shaded || scr->selected_windows) {
1512 if (!scr->selected_windows) {
1513 wWindowMove(wwin, src_x+off_x, src_y+off_y);
1514 wWindowSynthConfigureNotify(wwin);
1515 } else {
1516 int i;
1517 WMBag *bag = scr->selected_windows;
1518 doWindowMove(wwin,scr->selected_windows,off_x,off_y);
1519 for (i = 0; i < WMGetBagItemCount(bag); i++) {
1520 wWindowSynthConfigureNotify(WMGetFromBag(bag, i));
1523 } else {
1524 if (wwin->client.width != ww)
1525 wwin->flags.user_changed_width = 1;
1527 if (wwin->client.height != wh - vert_border)
1528 wwin->flags.user_changed_height = 1;
1530 wWindowConfigure(wwin, src_x+off_x, src_y+off_y,
1531 ww, wh - vert_border);
1532 wWindowSynthConfigureNotify(wwin);
1534 wWindowChangeWorkspace(wwin, scr->current_workspace);
1535 wSetFocusTo(scr, wwin);
1537 return 1;
1544 *----------------------------------------------------------------------
1545 * wMouseMoveWindow--
1546 * Move the named window and the other selected ones (if any),
1547 * interactively. Also shows the position of the window, if only one
1548 * window is being moved.
1549 * If the window is not on the selected window list, the selected
1550 * windows are deselected.
1551 * If shift is pressed during the operation, the position display
1552 * is changed to another type.
1554 * Returns:
1555 * True if the window was moved, False otherwise.
1557 * Side effects:
1558 * The window(s) position is changed, and the client(s) are
1559 * notified about that.
1560 * The position display configuration may be changed.
1561 *----------------------------------------------------------------------
1564 wMouseMoveWindow(WWindow *wwin, XEvent *ev)
1566 WScreen *scr = wwin->screen_ptr;
1567 XEvent event;
1568 Window root = scr->root_win;
1569 KeyCode shiftl, shiftr;
1570 Bool done = False;
1571 int started = 0;
1572 int warped = 0;
1573 /* This needs not to change while moving, else bad things can happen */
1574 int opaqueMove = wPreferences.opaque_move;
1575 MoveData moveData;
1576 #ifdef GHOST_WINDOW_MOVE
1577 RImage *rimg;
1579 rimg = InitGhostWindowMove(scr);
1580 #endif
1583 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1584 XSetWindowAttributes attr;
1586 attr.save_under = True;
1587 XChangeWindowAttributes(dpy, wwin->frame->core->window,
1588 CWSaveUnder, &attr);
1592 initMoveData(wwin, &moveData);
1594 moveData.mouseX = ev->xmotion.x_root;
1595 moveData.mouseY = ev->xmotion.y_root;
1597 if (!wwin->flags.selected) {
1598 /* this window is not selected, unselect others and move only wwin */
1599 wUnselectWindows(scr);
1601 #ifdef DEBUG
1602 puts("Moving window");
1603 #endif
1604 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1605 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1606 while (!done) {
1607 if (warped) {
1608 int junk;
1609 Window junkw;
1611 /* XWarpPointer() doesn't seem to generate Motion events, so
1612 we've got to simulate them */
1613 XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
1614 &event.xmotion.y_root, &junk, &junk,
1615 (unsigned *) &junk);
1616 } else {
1617 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
1618 | ButtonReleaseMask | ButtonPressMask | ExposureMask,
1619 &event);
1621 if (event.type == MotionNotify) {
1622 /* compress MotionNotify events */
1623 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
1624 if (!checkMouseSamplingRate(&event))
1625 continue;
1628 switch (event.type) {
1629 case KeyPress:
1630 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1631 && started && !scr->selected_windows) {
1633 if (!opaqueMove) {
1634 drawFrames(wwin, scr->selected_windows,
1635 moveData.realX - wwin->frame_x,
1636 moveData.realY - wwin->frame_y);
1639 if (wPreferences.move_display == WDIS_NEW
1640 && !scr->selected_windows) {
1641 showPosition(wwin, moveData.realX, moveData.realY);
1642 XUngrabServer(dpy);
1644 cyclePositionDisplay(wwin, moveData.realX, moveData.realY,
1645 moveData.winWidth, moveData.winHeight);
1647 if (wPreferences.move_display == WDIS_NEW
1648 && !scr->selected_windows) {
1649 XGrabServer(dpy);
1650 showPosition(wwin, moveData.realX, moveData.realY);
1653 if (!opaqueMove) {
1654 drawFrames(wwin, scr->selected_windows,
1655 moveData.realX - wwin->frame_x,
1656 moveData.realY - wwin->frame_y);
1659 break;
1661 case MotionNotify:
1662 if (started) {
1663 updateWindowPosition(wwin, &moveData,
1664 scr->selected_windows == NULL
1665 && wPreferences.edge_resistance > 0,
1666 opaqueMove,
1667 event.xmotion.x_root,
1668 event.xmotion.y_root);
1670 if (!warped && !wPreferences.no_autowrap) {
1671 int oldWorkspace = scr->current_workspace;
1673 if (wPreferences.move_display == WDIS_NEW
1674 && !scr->selected_windows) {
1675 showPosition(wwin, moveData.realX, moveData.realY);
1676 XUngrabServer(dpy);
1678 if (!opaqueMove) {
1679 drawFrames(wwin, scr->selected_windows,
1680 moveData.realX - wwin->frame_x,
1681 moveData.realY - wwin->frame_y);
1683 if (checkWorkspaceChange(wwin, &moveData, opaqueMove)) {
1684 if (scr->current_workspace != oldWorkspace
1685 && wPreferences.edge_resistance > 0
1686 && scr->selected_windows == NULL)
1687 updateMoveData(wwin, &moveData);
1688 warped = 1;
1690 if (!opaqueMove) {
1691 drawFrames(wwin, scr->selected_windows,
1692 moveData.realX - wwin->frame_x,
1693 moveData.realY - wwin->frame_y);
1695 if (wPreferences.move_display == WDIS_NEW
1696 && !scr->selected_windows) {
1697 XSync(dpy, False);
1698 showPosition(wwin, moveData.realX, moveData.realY);
1699 XGrabServer(dpy);
1701 } else {
1702 warped = 0;
1704 } else if (abs(ev->xmotion.x_root - event.xmotion.x_root) >= MOVE_THRESHOLD
1705 || abs(ev->xmotion.y_root - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1707 XChangeActivePointerGrab(dpy, ButtonMotionMask
1708 | ButtonReleaseMask | ButtonPressMask,
1709 wCursor[WCUR_MOVE], CurrentTime);
1710 started = 1;
1711 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
1712 CurrentTime);
1714 if (!scr->selected_windows)
1715 mapPositionDisplay(wwin, moveData.realX, moveData.realY,
1716 moveData.winWidth, moveData.winHeight);
1718 if (started && !opaqueMove)
1719 drawFrames(wwin, scr->selected_windows, 0, 0);
1721 if (!opaqueMove || (wPreferences.move_display==WDIS_NEW
1722 && !scr->selected_windows)) {
1723 XGrabServer(dpy);
1724 if (wPreferences.move_display==WDIS_NEW)
1725 showPosition(wwin, moveData.realX, moveData.realY);
1728 break;
1730 case ButtonPress:
1731 break;
1733 case ButtonRelease:
1734 if (event.xbutton.button != ev->xbutton.button)
1735 break;
1737 if (started) {
1738 if (!opaqueMove) {
1739 drawFrames(wwin, scr->selected_windows,
1740 moveData.realX - wwin->frame_x,
1741 moveData.realY - wwin->frame_y);
1742 XSync(dpy, 0);
1743 doWindowMove(wwin, scr->selected_windows,
1744 moveData.realX - wwin->frame_x,
1745 moveData.realY - wwin->frame_y);
1747 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
1748 wWindowSynthConfigureNotify(wwin);
1749 #endif
1750 XUngrabKeyboard(dpy, CurrentTime);
1751 XUngrabServer(dpy);
1752 if (!opaqueMove) {
1753 wWindowChangeWorkspace(wwin, scr->current_workspace);
1754 wSetFocusTo(scr, wwin);
1756 if (wPreferences.move_display == WDIS_NEW)
1757 showPosition(wwin, moveData.realX, moveData.realY);
1759 if (!scr->selected_windows) {
1760 /* get rid of the geometry window */
1761 unmapPositionDisplay(wwin);
1764 #ifdef DEBUG
1765 puts("End move window");
1766 #endif
1767 done = True;
1768 break;
1770 default:
1771 if (started && !opaqueMove) {
1772 drawFrames(wwin, scr->selected_windows,
1773 moveData.realX - wwin->frame_x,
1774 moveData.realY - wwin->frame_y);
1775 XUngrabServer(dpy);
1776 WMHandleEvent(&event);
1777 XSync(dpy, False);
1778 XGrabServer(dpy);
1779 drawFrames(wwin, scr->selected_windows,
1780 moveData.realX - wwin->frame_x,
1781 moveData.realY - wwin->frame_y);
1782 } else {
1783 WMHandleEvent(&event);
1785 break;
1789 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1790 XSetWindowAttributes attr;
1793 attr.save_under = False;
1794 XChangeWindowAttributes(dpy, wwin->frame->core->window,
1795 CWSaveUnder, &attr);
1799 freeMoveData(&moveData);
1801 return started;
1805 #define RESIZEBAR 1
1806 #define HCONSTRAIN 2
1808 static int
1809 getResizeDirection(WWindow *wwin, int x, int y, int dx, int dy,
1810 int flags)
1812 int w = wwin->frame->core->width - 1;
1813 int cw = wwin->frame->resizebar_corner_width;
1814 int dir;
1816 /* if not resizing through the resizebar */
1817 if (!(flags & RESIZEBAR)) {
1818 int xdir = (abs(x) < (wwin->client.width/2)) ? LEFT : RIGHT;
1819 int ydir = (abs(y) < (wwin->client.height/2)) ? UP : DOWN;
1820 if (abs(dx) < 2 || abs(dy) < 2) {
1821 if (abs(dy) > abs(dx))
1822 xdir = 0;
1823 else
1824 ydir = 0;
1826 return (xdir | ydir);
1829 /* window is too narrow. allow diagonal resize */
1830 if (cw * 2 >= w) {
1831 int ydir;
1833 if (flags & HCONSTRAIN)
1834 ydir = 0;
1835 else
1836 ydir = DOWN;
1837 if (x < cw)
1838 return (LEFT | ydir);
1839 else
1840 return (RIGHT | ydir);
1842 /* vertical resize */
1843 if ((x > cw) && (x < w - cw))
1844 return DOWN;
1846 if (x < cw)
1847 dir = LEFT;
1848 else
1849 dir = RIGHT;
1851 if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
1852 dir |= DOWN;
1854 return dir;
1858 void
1859 wMouseResizeWindow(WWindow *wwin, XEvent *ev)
1861 XEvent event;
1862 WScreen *scr = wwin->screen_ptr;
1863 Window root = scr->root_win;
1864 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1865 int fw = wwin->frame->core->width;
1866 int fh = wwin->frame->core->height;
1867 int fx = wwin->frame_x;
1868 int fy = wwin->frame_y;
1869 int is_resizebar = (wwin->frame->resizebar
1870 && ev->xany.window==wwin->frame->resizebar->window);
1871 int orig_x, orig_y;
1872 int started;
1873 int dw, dh;
1874 int rw = fw, rh = fh;
1875 int rx1, ry1, rx2, ry2;
1876 int res = 0;
1877 KeyCode shiftl, shiftr;
1878 int h = 0;
1879 int orig_fx = fx;
1880 int orig_fy = fy;
1881 int orig_fw = fw;
1882 int orig_fh = fh;
1884 if (wwin->flags.shaded) {
1885 wwarning("internal error: tryein");
1886 return;
1888 orig_x = ev->xbutton.x_root;
1889 orig_y = ev->xbutton.y_root;
1891 started = 0;
1892 #ifdef DEBUG
1893 puts("Resizing window");
1894 #endif
1896 wUnselectWindows(scr);
1897 rx1 = fx;
1898 rx2 = fx + fw - 1;
1899 ry1 = fy;
1900 ry2 = fy + fh - 1;
1901 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1902 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1903 if (!WFLAGP(wwin, no_titlebar))
1904 h = WMFontHeight(wwin->screen_ptr->title_font) + TITLEBAR_EXTRA_HEIGHT;
1905 else
1906 h = 0;
1907 while (1) {
1908 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask | ButtonReleaseMask
1909 | ButtonPressMask | ExposureMask, &event);
1911 if (!checkMouseSamplingRate(&event))
1912 continue;
1914 switch (event.type) {
1915 case KeyPress:
1916 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1917 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1918 && started) {
1919 drawTransparentFrame(wwin, fx, fy, fw, fh);
1920 cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
1921 drawTransparentFrame(wwin, fx, fy, fw, fh);
1923 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1924 break;
1926 case MotionNotify:
1927 if (started) {
1928 dw = 0;
1929 dh = 0;
1931 orig_fx = fx;
1932 orig_fy = fy;
1933 orig_fw = fw;
1934 orig_fh = fh;
1936 if (res & LEFT)
1937 dw = orig_x - event.xmotion.x_root;
1938 else if (res & RIGHT)
1939 dw = event.xmotion.x_root - orig_x;
1940 if (res & UP)
1941 dh = orig_y - event.xmotion.y_root;
1942 else if (res & DOWN)
1943 dh = event.xmotion.y_root - orig_y;
1945 orig_x = event.xmotion.x_root;
1946 orig_y = event.xmotion.y_root;
1948 rw += dw;
1949 rh += dh;
1950 fw = rw;
1951 fh = rh - vert_border;
1952 wWindowConstrainSize(wwin, &fw, &fh);
1953 fh += vert_border;
1954 if (res & LEFT)
1955 fx = rx2 - fw + 1;
1956 else if (res & RIGHT)
1957 fx = rx1;
1958 if (res & UP)
1959 fy = ry2 - fh + 1;
1960 else if (res & DOWN)
1961 fy = ry1;
1962 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
1963 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1964 int tx, ty;
1965 Window junkw;
1966 int flags;
1968 XTranslateCoordinates(dpy, root, wwin->frame->core->window,
1969 orig_x, orig_y, &tx, &ty, &junkw);
1971 /* check if resizing through resizebar */
1972 if (is_resizebar)
1973 flags = RESIZEBAR;
1974 else
1975 flags = 0;
1977 if (is_resizebar && ((ev->xbutton.state & ShiftMask)
1978 || abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
1979 flags |= HCONSTRAIN;
1981 res = getResizeDirection(wwin, tx, ty,
1982 orig_x - event.xmotion.x_root,
1983 orig_y - event.xmotion.y_root, flags);
1985 XChangeActivePointerGrab(dpy, ButtonMotionMask
1986 | ButtonReleaseMask | ButtonPressMask,
1987 wCursor[WCUR_RESIZE], CurrentTime);
1988 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
1989 CurrentTime);
1991 XGrabServer(dpy);
1993 /* Draw the resize frame for the first time. */
1994 mapGeometryDisplay(wwin, fx, fy, fw, fh);
1996 drawTransparentFrame(wwin, fx, fy, fw, fh);
1998 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2000 started = 1;
2002 if (started) {
2003 if (wPreferences.size_display == WDIS_FRAME_CENTER) {
2004 drawTransparentFrame(wwin, orig_fx, orig_fy,
2005 orig_fw, orig_fh);
2006 moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
2007 drawTransparentFrame(wwin, fx, fy, fw, fh);
2008 } else {
2009 drawTransparentFrame(wwin, orig_fx, orig_fy,
2010 orig_fw, orig_fh);
2011 drawTransparentFrame(wwin, fx, fy, fw, fh);
2013 if (fh != orig_fh || fw != orig_fw) {
2014 if (wPreferences.size_display == WDIS_NEW) {
2015 showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw,
2016 orig_fy + orig_fh, res);
2018 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2021 break;
2023 case ButtonPress:
2024 break;
2026 case ButtonRelease:
2027 if (event.xbutton.button != ev->xbutton.button)
2028 break;
2030 if (started) {
2031 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2033 drawTransparentFrame(wwin, fx, fy, fw, fh);
2035 XUngrabKeyboard(dpy, CurrentTime);
2036 unmapGeometryDisplay(wwin);
2037 XUngrabServer(dpy);
2039 if (wwin->client.width != fw)
2040 wwin->flags.user_changed_width = 1;
2042 if (wwin->client.height != fh - vert_border)
2043 wwin->flags.user_changed_height = 1;
2045 wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
2047 #ifdef DEBUG
2048 puts("End resize window");
2049 #endif
2050 return;
2052 default:
2053 WMHandleEvent(&event);
2058 #undef LEFT
2059 #undef RIGHT
2060 #undef HORIZONTAL
2061 #undef UP
2062 #undef DOWN
2063 #undef VERTICAL
2064 #undef HCONSTRAIN
2065 #undef RESIZEBAR
2067 void
2068 wUnselectWindows(WScreen *scr)
2070 WWindow *wwin;
2072 if (!scr->selected_windows)
2073 return;
2075 while (WMGetBagItemCount(scr->selected_windows)) {
2076 wwin = WMGetFromBag(scr->selected_windows, 0);
2077 if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
2078 wIconSelect(wwin->icon);
2080 wSelectWindow(wwin, False);
2082 WMFreeBag(scr->selected_windows);
2083 scr->selected_windows = NULL;
2086 #ifndef LITE
2087 static void
2088 selectWindowsInside(WScreen *scr, int x1, int y1, int x2, int y2)
2090 WWindow *tmpw;
2092 /* select the windows and put them in the selected window list */
2093 tmpw = scr->focused_window;
2094 while (tmpw != NULL) {
2095 if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
2096 if ((tmpw->frame->workspace == scr->current_workspace
2097 || IS_OMNIPRESENT(tmpw))
2098 && (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1)
2099 && (tmpw->frame->core->width + tmpw->frame_x <= x2)
2100 && (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
2101 wSelectWindow(tmpw, True);
2104 tmpw = tmpw->prev;
2109 void
2110 wSelectWindows(WScreen *scr, XEvent *ev)
2112 XEvent event;
2113 Window root = scr->root_win;
2114 GC gc = scr->frame_gc;
2115 int xp = ev->xbutton.x_root;
2116 int yp = ev->xbutton.y_root;
2117 int w = 0, h = 0;
2118 int nx = xp, ny = yp, ox = xp, oy = yp, update_selection = 0;
2119 XSegment segments[8]; /* 8 segments is the most possible */
2120 /* it may be beneficial to use */
2121 /* XDrawRectangle for 8 segment case */
2122 int nsegs = 0;
2125 #ifdef DEBUG
2126 puts("Selecting windows");
2127 #endif
2128 if (XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
2129 | ButtonMotionMask | ButtonReleaseMask | ButtonPressMask
2130 | EnterWindowMask | LeaveWindowMask , GrabModeAsync,
2131 GrabModeAsync, None, wCursor[WCUR_DEFAULT],
2132 CurrentTime) != Success) {
2133 return;
2135 XGrabServer(dpy);
2137 wUnselectWindows(scr);
2139 while (1) {
2140 update_selection = 0;
2142 WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask | LeaveWindowMask
2143 | EnterWindowMask | ButtonPressMask,
2144 &event);
2146 if (!checkMouseSamplingRate(&event))
2147 continue;
2149 nsegs = 0;
2150 switch (event.type) {
2151 case LeaveNotify:
2152 case EnterNotify:
2153 #ifdef DEBUG
2154 dbputs("got Enter/LeaveNotify in selection");
2155 #endif
2156 nx = event.xcrossing.x_root;
2157 ny = event.xcrossing.y_root;
2158 update_selection = 1;
2159 break;
2162 case MotionNotify:
2163 #ifdef DEBUG
2164 dbputs("got motionevent in selection");
2165 #endif
2166 nx = event.xmotion.x_root;
2167 ny = event.xmotion.y_root;
2168 update_selection = 1;
2169 break;
2171 case ButtonPress:
2172 break;
2174 case ButtonRelease:
2175 if (event.xbutton.button != ev->xbutton.button)
2176 break;
2178 if(nx > xp) w = nx - xp;
2179 else if(nx < xp) {
2180 w = xp - nx;
2181 xp = nx;
2182 } else w = 0;
2184 if(ny > yp) h = ny - yp;
2185 else if(ny < yp) {
2186 h = yp - ny;
2187 yp = ny;
2188 } else h = 0;
2190 XDrawRectangle(dpy, root, gc, xp, yp, w, h);
2191 XUngrabServer(dpy);
2192 XUngrabPointer(dpy, CurrentTime);
2193 selectWindowsInside(scr, xp, yp, w + xp, h + yp);
2195 #ifdef KWM_HINTS
2196 wKWMSelectRootRegion(scr, xp, yp, w, h,
2197 event.xbutton.state & ControlMask);
2198 #endif /* KWM_HINTS */
2200 #ifdef DEBUG
2201 dbputs("End window selection");
2202 #endif
2203 return;
2205 default:
2206 #ifdef DEBUG
2207 dbputs("unknown event");
2208 dbprintf("type: %u\n", event.type);
2209 #endif
2210 WMHandleEvent(&event);
2211 break;
2214 if(update_selection) {
2215 /* stuff to change for movement along X axis */
2216 if(nx != ox) {
2218 /* erase old vertical line */
2219 /* only if old vertical line exists */
2220 /* and only if its different from other vertical line */
2221 if(yp != oy && ox != xp) {
2222 segments[nsegs].x1 = ox;
2223 segments[nsegs].y1 = yp;
2224 segments[nsegs].x2 = ox;
2225 segments[nsegs].y2 = oy;
2226 nsegs++;
2229 /* draw new vertical line */
2230 /* only if new vertical line exists */
2231 /* and only if its different from the other vertical line */
2232 if(yp != ny && nx != xp) {
2233 segments[nsegs].x1 = nx;
2234 segments[nsegs].y1 = yp;
2235 segments[nsegs].x2 = nx;
2236 segments[nsegs].y2 = ny;
2237 nsegs++;
2240 /* difference along x axis from old to new on ny horizontal */
2241 /* only if our mouse doesnt move along Y, otherwise this gets */
2242 /* done elsewhere */
2243 if(ny == oy && nx != xp) {
2244 segments[nsegs].x1 = ox;
2245 segments[nsegs].y1 = ny;
2246 segments[nsegs].x2 = nx;
2247 segments[nsegs].y2 = ny;
2248 nsegs++;
2251 /* difference along x axis from old to new on yp horizontal */
2252 segments[nsegs].x1 = nx;
2253 segments[nsegs].y1 = yp;
2254 segments[nsegs].x2 = ox;
2255 segments[nsegs].y2 = yp;
2256 nsegs++;
2261 /* now for stuff to change for movement along Y axis */
2263 if(ny != oy) {
2264 /* erase old horizontal line */
2265 /* only if old horizontal line exists */
2266 /* and only if its different from other horizontal line */
2267 if(xp != ox && oy != yp) {
2268 segments[nsegs].x1 = ox;
2269 segments[nsegs].y1 = oy;
2270 segments[nsegs].x2 = xp;
2271 segments[nsegs].y2 = oy;
2272 nsegs++;
2275 /* draw new horizontal line */
2276 /* only if horizontal line exists, and if its different from other */
2277 if(xp != nx && ny != yp) {
2278 segments[nsegs].x1 = nx;
2279 segments[nsegs].y1 = ny;
2280 segments[nsegs].x2 = xp;
2281 segments[nsegs].y2 = ny;
2282 nsegs++;
2285 /* difference along y axis from old to new on nx vertical */
2286 /* only if no movement along x axis */
2287 /* and only if we dont have duplicate lines */
2288 if(nx == ox && nx != xp) {
2289 segments[nsegs].x1 = nx;
2290 segments[nsegs].y1 = oy;
2291 segments[nsegs].x2 = nx;
2292 segments[nsegs].y2 = ny;
2293 nsegs++;
2296 /* difference along y axis from old to new on xp vertical */
2297 segments[nsegs].x1 = xp;
2298 segments[nsegs].y1 = oy;
2299 segments[nsegs].x2 = xp;
2300 segments[nsegs].y2 = ny;
2301 nsegs++;
2304 ox = nx;
2305 oy = ny;
2306 XDrawSegments(dpy, root, gc, segments, nsegs);
2310 #endif /* !LITE */
2312 void
2313 InteractivePlaceWindow(WWindow *wwin, int *x_ret, int *y_ret,
2314 unsigned width, unsigned height)
2316 WScreen *scr = wwin->screen_ptr;
2317 Window root = scr->root_win;
2318 int x, y, h = 0;
2319 XEvent event;
2320 KeyCode shiftl, shiftr;
2321 Window junkw;
2322 int junk;
2324 if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
2325 GrabModeAsync, GrabModeAsync, None,
2326 wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
2327 *x_ret = 0;
2328 *y_ret = 0;
2329 return;
2331 if (!WFLAGP(wwin, no_titlebar)) {
2332 h = WMFontHeight(scr->title_font) + TITLEBAR_EXTRA_HEIGHT;
2333 height += h;
2335 if (!WFLAGP(wwin, no_resizebar)) {
2336 height += RESIZEBAR_HEIGHT;
2338 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
2339 XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk,
2340 (unsigned *) &junk);
2341 mapPositionDisplay(wwin, x - width/2, y - h/2, width, height);
2343 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2345 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
2346 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
2347 while (1) {
2348 WMMaskEvent(dpy, PointerMotionMask|ButtonPressMask|ExposureMask|KeyPressMask,
2349 &event);
2351 if (!checkMouseSamplingRate(&event))
2352 continue;
2354 switch (event.type) {
2355 case KeyPress:
2356 if ((event.xkey.keycode == shiftl)
2357 || (event.xkey.keycode == shiftr)) {
2358 drawTransparentFrame(wwin,
2359 x - width/2, y - h/2, width, height);
2360 cyclePositionDisplay(wwin,
2361 x - width/2, y - h/2, width, height);
2362 drawTransparentFrame(wwin,
2363 x - width/2, y - h/2, width, height);
2365 break;
2367 case MotionNotify:
2368 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2370 x = event.xmotion.x_root;
2371 y = event.xmotion.y_root;
2373 if (wPreferences.move_display == WDIS_FRAME_CENTER)
2374 moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
2376 showPosition(wwin, x - width/2, y - h/2);
2378 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2380 break;
2382 case ButtonPress:
2383 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2384 XSync(dpy, 0);
2385 *x_ret = x - width/2;
2386 *y_ret = y - h/2;
2387 XUngrabPointer(dpy, CurrentTime);
2388 XUngrabKeyboard(dpy, CurrentTime);
2389 /* get rid of the geometry window */
2390 unmapPositionDisplay(wwin);
2391 return;
2393 default:
2394 WMHandleEvent(&event);
2395 break;