Added get-wings-flags and get-wutil-flags
[wmaker-crm.git] / src / moveres.c
blob58b1cf600e435789257261c911441b25c6b491ec
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;
70 void
71 wGetGeometryWindowSize(WScreen *scr, unsigned int *width,
72 unsigned int *height)
74 *width = WMWidthOfString(scr->info_text_font, "-8888 x -8888", 13);
76 *height = (6 * WMFontHeight(scr->info_text_font)) / 4 - 1;
81 *----------------------------------------------------------------------
82 * checkMouseSamplingRate-
83 * For lowering the mouse motion sampling rate for machines where
84 * it's too high (SGIs). If it returns False then the event should be
85 * ignored.
86 *----------------------------------------------------------------------
88 static Bool
89 checkMouseSamplingRate(XEvent *ev)
91 static Time previousMotion = 0;
93 if (ev->type == MotionNotify) {
94 if (ev->xmotion.time - previousMotion < DELAY_BETWEEN_MOUSE_SAMPLING) {
95 return False;
96 } else {
97 previousMotion = ev->xmotion.time;
100 return True;
106 *----------------------------------------------------------------------
107 * moveGeometryDisplayCentered
109 * routine that moves the geometry/position window on scr so it is
110 * centered over the given coordinates (x,y). Also the window position
111 * is clamped so it stays on the screen at all times.
112 *----------------------------------------------------------------------
114 static void
115 moveGeometryDisplayCentered(WScreen *scr, int x, int y)
117 x -= scr->geometry_display_width / 2;
118 y -= scr->geometry_display_height / 2;
120 if (x < 1)
121 x = 1;
122 else if (x > (scr->scr_width - scr->geometry_display_width - 3))
123 x = scr->scr_width - scr->geometry_display_width - 3;
125 if (y < 1)
126 y = 1;
127 else if (y > (scr->scr_height - scr->geometry_display_height - 3))
128 y = scr->scr_height - scr->geometry_display_height - 3;
130 XMoveWindow(dpy, scr->geometry_display, x, y);
134 static void
135 showPosition(WWindow *wwin, int x, int y)
137 WScreen *scr = wwin->screen_ptr;
138 GC gc = scr->info_text_gc;
139 char num[16];
140 int fw, fh;
142 if (wPreferences.move_display == WDIS_NEW) {
143 #if 1
144 int width = wwin->frame->core->width;
145 int height = wwin->frame->core->height;
147 GC lgc = scr->line_gc;
148 XSetForeground(dpy, lgc, scr->line_pixel);
149 sprintf(num, "%i", x);
151 XDrawLine(dpy, scr->root_win, lgc, 0, y-1, scr->scr_width, y-1);
152 XDrawLine(dpy, scr->root_win, lgc, 0, y+height+2, scr->scr_width,
153 y+height+2);
154 XDrawLine(dpy, scr->root_win, lgc, x-1, 0, x-1, scr->scr_height);
155 XDrawLine(dpy, scr->root_win, lgc, x+width+2, 0, x+width+2,
156 scr->scr_height);
157 #endif
158 } else {
159 XClearArea(dpy, scr->geometry_display, 1, 1,
160 scr->geometry_display_width-2, scr->geometry_display_height-2,
161 False);
162 sprintf(num, "%+i %-+i", x, y);
163 fw = WMWidthOfString(scr->info_text_font, num, strlen(num));
165 XSetForeground(dpy, gc, scr->black_pixel);
167 fh = WMFontHeight(scr->info_text_font);
168 WMDrawString(scr->wmscreen, scr->geometry_display, gc,
169 scr->info_text_font,
170 (scr->geometry_display_width - 2 - fw) / 2,
171 (scr->geometry_display_height-fh)/2, num, strlen(num));
172 wDrawBevel(scr->geometry_display, scr->geometry_display_width+1,
173 scr->geometry_display_height+1,
174 scr->widget_texture, WREL_RAISED);
179 static void
180 cyclePositionDisplay(WWindow *wwin, int x, int y, int w, int h)
182 WScreen *scr = wwin->screen_ptr;
184 wPreferences.move_display++;
185 wPreferences.move_display %= NUM_DISPLAYS;
187 if (wPreferences.move_display == WDIS_NEW) {
188 XUnmapWindow(dpy, scr->geometry_display);
189 } else {
190 if (wPreferences.move_display == WDIS_CENTER) {
191 moveGeometryDisplayCentered(scr,
192 scr->scr_width/2, scr->scr_height/2);
193 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
194 moveGeometryDisplayCentered(scr, 1, 1);
195 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
196 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
198 XMapRaised(dpy, scr->geometry_display);
203 static void
204 mapPositionDisplay(WWindow *wwin, int x, int y, int w, int h)
206 WScreen *scr = wwin->screen_ptr;
208 if (wPreferences.move_display == WDIS_NEW) {
209 return;
210 } else if (wPreferences.move_display == WDIS_CENTER) {
211 moveGeometryDisplayCentered(scr, scr->scr_width / 2,
212 scr->scr_height / 2);
213 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
214 moveGeometryDisplayCentered(scr, 1, 1);
215 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
216 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
218 XMapRaised(dpy, scr->geometry_display);
219 showPosition(wwin, x, y);
222 #define unmapPositionDisplay(w) \
223 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
226 static void
227 showGeometry(WWindow *wwin, int x1, int y1, int x2, int y2, int direction)
229 WScreen *scr = wwin->screen_ptr;
230 Window root = scr->root_win;
231 GC gc = scr->line_gc;
232 int ty, by, my, x, y, mx, s;
233 char num[16];
234 XSegment segment[4];
235 int fw, fh;
237 ty = y1 + wwin->frame->top_width;
238 by = y2 - wwin->frame->bottom_width;
239 fw = WMWidthOfString(scr->info_text_font, "8888", 4);
240 fh = WMFontHeight(scr->info_text_font);
242 if (wPreferences.size_display == WDIS_NEW) {
243 XSetForeground(dpy, gc, scr->line_pixel);
245 /* vertical geometry */
246 if (((direction & LEFT) && (x2 < scr->scr_width - fw)) || (x1 < fw)) {
247 x = x2;
248 s = -15;
249 } else {
250 x = x1;
251 s = 15;
253 my = (ty + by) / 2;
255 /* top arrow */
256 /* end bar */
257 segment[0].x1 = x - (s + 6); segment[0].y1 = ty;
258 segment[0].x2 = x - (s - 10); segment[0].y2 = ty;
260 /* arrowhead */
261 segment[1].x1 = x - (s - 2); segment[1].y1 = ty + 1;
262 segment[1].x2 = x - (s - 5); segment[1].y2 = ty + 7;
264 segment[2].x1 = x - (s - 2); segment[2].y1 = ty + 1;
265 segment[2].x2 = x - (s + 1); segment[2].y2 = ty + 7;
267 /* line */
268 segment[3].x1 = x - (s - 2); segment[3].y1 = ty + 1;
269 segment[3].x2 = x - (s - 2); segment[3].y2 = my - fh/2 - 1;
271 XDrawSegments(dpy, root, gc, segment, 4);
273 /* bottom arrow */
274 /* end bar */
275 segment[0].y1 = by;
276 segment[0].y2 = by;
278 /* arrowhead */
279 segment[1].y1 = by - 1;
280 segment[1].y2 = by - 7;
282 segment[2].y1 = by - 1;
283 segment[2].y2 = by - 7;
285 /* line */
286 segment[3].y1 = my + fh/2 + 2;
287 segment[3].y2 = by - 1;
289 XDrawSegments(dpy, root, gc, segment, 4);
291 sprintf(num, "%i", (by - ty - wwin->normal_hints->base_height) /
292 wwin->normal_hints->height_inc);
293 fw = WMWidthOfString(scr->info_text_font, num, strlen(num));
295 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
297 /* Display the height. */
298 WMDrawString(scr->wmscreen, root, gc, scr->info_text_font,
299 x - s + 3 - fw/2, my - fh/2 + 1, num, strlen(num));
300 XSetForeground(dpy, gc, scr->line_pixel);
301 /* horizontal geometry */
302 if (y1 < 15) {
303 y = y2;
304 s = -15;
305 } else {
306 y = y1;
307 s = 15;
309 mx = x1 + (x2 - x1)/2;
310 sprintf(num, "%i", (x2 - x1 - wwin->normal_hints->base_width) /
311 wwin->normal_hints->width_inc);
312 fw = WMWidthOfString(scr->info_text_font, num, strlen(num));
314 /* left arrow */
315 /* end bar */
316 segment[0].x1 = x1; segment[0].y1 = y - (s + 6);
317 segment[0].x2 = x1; segment[0].y2 = y - (s - 10);
319 /* arrowhead */
320 segment[1].x1 = x1 + 7; segment[1].y1 = y - (s + 1);
321 segment[1].x2 = x1 + 1; segment[1].y2 = y - (s - 2);
323 segment[2].x1 = x1 + 1; segment[2].y1 = y - (s - 2);
324 segment[2].x2 = x1 + 7; segment[2].y2 = y - (s - 5);
326 /* line */
327 segment[3].x1 = x1 + 1; segment[3].y1 = y - (s - 2);
328 segment[3].x2 = mx - fw/2 - 2; segment[3].y2 = y - (s - 2);
330 XDrawSegments(dpy, root, gc, segment, 4);
332 /* right arrow */
333 /* end bar */
334 segment[0].x1 = x2 + 1;
335 segment[0].x2 = x2 + 1;
337 /* arrowhead */
338 segment[1].x1 = x2 - 6;
339 segment[1].x2 = x2;
341 segment[2].x1 = x2;
342 segment[2].x2 = x2 - 6;
344 /* line */
345 segment[3].x1 = mx + fw/2 + 2;
346 segment[3].x2 = x2;
348 XDrawSegments(dpy, root, gc, segment, 4);
350 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
352 /* Display the width. */
353 WMDrawString(scr->wmscreen, root, gc, scr->info_text_font,
354 mx - fw/2 + 1, y - s - fh/2 + 1, num, strlen(num));
355 } else {
356 XClearArea(dpy, scr->geometry_display, 1, 1,
357 scr->geometry_display_width-2, scr->geometry_display_height-2,
358 False);
359 sprintf(num, "%i x %-i", (x2 - x1 - wwin->normal_hints->base_width)
360 / wwin->normal_hints->width_inc,
361 (by - ty - wwin->normal_hints->base_height)
362 / wwin->normal_hints->height_inc);
363 fw = WMWidthOfString(scr->info_text_font, num, strlen(num));
365 XSetForeground(dpy, scr->info_text_gc, scr->black_pixel);
367 /* Display the height. */
368 WMDrawString(scr->wmscreen, scr->geometry_display, scr->info_text_gc,
369 scr->info_text_font,
370 (scr->geometry_display_width-fw)/2,
371 (scr->geometry_display_height-fh)/2, num, strlen(num));
372 wDrawBevel(scr->geometry_display, scr->geometry_display_width+1,
373 scr->geometry_display_height+1,
374 scr->widget_texture, WREL_RAISED);
379 static void
380 cycleGeometryDisplay(WWindow *wwin, int x, int y, int w, int h, int dir)
382 WScreen *scr = wwin->screen_ptr;
384 wPreferences.size_display++;
385 wPreferences.size_display %= NUM_DISPLAYS;
387 if (wPreferences.size_display == WDIS_NEW) {
388 XUnmapWindow(dpy, scr->geometry_display);
389 } else {
390 if (wPreferences.size_display == WDIS_CENTER) {
391 moveGeometryDisplayCentered(scr,
392 scr->scr_width / 2, scr->scr_height / 2);
393 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
394 moveGeometryDisplayCentered(scr, 1, 1);
395 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
396 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
398 XMapRaised(dpy, scr->geometry_display);
399 showGeometry(wwin, x, y, x + w, y + h, dir);
404 static void
405 mapGeometryDisplay(WWindow *wwin, int x, int y, int w, int h)
407 WScreen *scr = wwin->screen_ptr;
409 if (wPreferences.size_display == WDIS_NEW)
410 return;
412 if (wPreferences.size_display == WDIS_CENTER) {
413 moveGeometryDisplayCentered(scr, scr->scr_width / 2,
414 scr->scr_height / 2);
415 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
416 moveGeometryDisplayCentered(scr, 1, 1);
417 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
418 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
420 XMapRaised(dpy, scr->geometry_display);
421 showGeometry(wwin, x, y, x + w, y + h, 0);
424 #define unmapGeometryDisplay(w) \
425 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
428 static void
429 doWindowMove(WWindow *wwin, WMBag *bag, int dx, int dy)
431 WWindow *tmpw;
432 int x, y;
433 int scr_width = wwin->screen_ptr->scr_width;
434 int scr_height = wwin->screen_ptr->scr_height;
436 if (!bag || !WMGetBagItemCount(bag)) {
437 wWindowMove(wwin, wwin->frame_x + dx, wwin->frame_y + dy);
438 } else {
439 int i;
440 for (i = 0; i < WMGetBagItemCount(bag); i++) {
441 tmpw = WMGetFromBag(bag, i);
442 x = tmpw->frame_x + dx;
443 y = tmpw->frame_y + dy;
445 /* don't let windows become unreachable */
447 if (x + (int)tmpw->frame->core->width < 20)
448 x = 20 - (int)tmpw->frame->core->width;
449 else if (x + 20 > scr_width)
450 x = scr_width - 20;
452 if (y + (int)tmpw->frame->core->height < 20)
453 y = 20 - (int)tmpw->frame->core->height;
454 else if (y + 20 > scr_height)
455 y = scr_height - 20;
457 wWindowMove(tmpw, x, y);
463 static void
464 drawTransparentFrame(WWindow *wwin, int x, int y, int width, int height)
466 Window root = wwin->screen_ptr->root_win;
467 GC gc = wwin->screen_ptr->frame_gc;
468 int h = 0;
469 int bottom = 0;
471 if (!WFLAGP(wwin, no_titlebar) && !wwin->flags.shaded) {
472 h = WMFontHeight(wwin->screen_ptr->title_font) + TITLEBAR_EXTRA_HEIGHT;
474 if (!WFLAGP(wwin, no_resizebar) && !wwin->flags.shaded) {
475 /* Can't use wwin-frame->bottom_width because, in some cases
476 (e.g. interactive placement), frame does not point to anything. */
477 bottom = RESIZEBAR_HEIGHT - 1;
479 XDrawRectangle(dpy, root, gc, x, y, width + 1, height + 1);
481 if (h > 0) {
482 XDrawLine(dpy, root, gc, x + 1, y + h, x + width + 1, y + h);
484 if (bottom > 0) {
485 XDrawLine(dpy, root, gc, x + 1,
486 y + height - bottom,
487 x + width + 1,
488 y + height - bottom);
493 static void
494 drawFrames(WWindow *wwin, WMBag *bag, int dx, int dy)
496 WWindow *tmpw;
497 int scr_width = wwin->screen_ptr->scr_width;
498 int scr_height = wwin->screen_ptr->scr_height;
499 int x, y;
501 if (!bag) {
503 x = wwin->frame_x + dx;
504 y = wwin->frame_y + dy;
506 drawTransparentFrame(wwin, x, y,
507 wwin->frame->core->width,
508 wwin->frame->core->height);
510 } else {
511 int i;
512 for (i = 0; i < WMGetBagItemCount(bag); i++) {
513 tmpw = WMGetFromBag(bag, i);
514 x = tmpw->frame_x + dx;
515 y = tmpw->frame_y + dy;
517 /* don't let windows become unreachable */
519 if (x + (int)tmpw->frame->core->width < 20)
520 x = 20 - (int)tmpw->frame->core->width;
521 else if (x + 20 > scr_width)
522 x = scr_width - 20;
524 if (y + (int)tmpw->frame->core->height < 20)
525 y = 20 - (int)tmpw->frame->core->height;
526 else if (y + 20 > scr_height)
527 y = scr_height - 20;
529 drawTransparentFrame(tmpw, x, y, tmpw->frame->core->width,
530 tmpw->frame->core->height);
537 static void
538 flushMotion()
540 XEvent ev;
542 XSync(dpy, False);
543 while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
547 static void
548 crossWorkspace(WScreen *scr, WWindow *wwin, int opaque_move,
549 int new_workspace, int rewind)
551 /* do not let window be unmapped */
552 if (opaque_move) {
553 wwin->flags.changing_workspace = 1;
554 wWindowChangeWorkspace(wwin, new_workspace);
556 /* go to new workspace */
557 wWorkspaceChange(scr, new_workspace);
559 wwin->flags.changing_workspace = 0;
561 if (rewind)
562 XWarpPointer(dpy, None, None, 0, 0, 0, 0, scr->scr_width - 20, 0);
563 else
564 XWarpPointer(dpy, None, None, 0, 0, 0, 0, -(scr->scr_width - 20), 0);
566 flushMotion();
568 if (!opaque_move) {
569 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
570 |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
571 GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
578 typedef struct {
579 /* arrays of WWindows sorted by the respective border position */
580 WWindow **topList; /* top border */
581 WWindow **leftList; /* left border */
582 WWindow **rightList; /* right border */
583 WWindow **bottomList; /* bottom border */
584 int count;
586 /* index of window in the above lists indicating the relative position
587 * of the window with the others */
588 int topIndex;
589 int leftIndex;
590 int rightIndex;
591 int bottomIndex;
593 int rubCount; /* for workspace switching */
595 int winWidth, winHeight; /* width/height of the window */
596 int realX, realY; /* actual position of the window */
597 int calcX, calcY; /* calculated position of window */
598 int omouseX, omouseY; /* old mouse position */
599 int mouseX, mouseY; /* last known position of the pointer */
600 } MoveData;
602 #define WTOP(w) (w)->frame_y
603 #define WLEFT(w) (w)->frame_x
604 #define WRIGHT(w) ((w)->frame_x + (int)(w)->frame->core->width + FRAME_BORDER_WIDTH)
605 #define WBOTTOM(w) ((w)->frame_y + (int)(w)->frame->core->height + FRAME_BORDER_WIDTH)
607 static int
608 compareWTop(const void *a, const void *b)
610 WWindow *wwin1 = *(WWindow**)a;
611 WWindow *wwin2 = *(WWindow**)b;
613 if (WTOP(wwin1) > WTOP(wwin2))
614 return -1;
615 else if (WTOP(wwin1) < WTOP(wwin2))
616 return 1;
617 else
618 return 0;
622 static int
623 compareWLeft(const void *a, const void *b)
625 WWindow *wwin1 = *(WWindow**)a;
626 WWindow *wwin2 = *(WWindow**)b;
628 if (WLEFT(wwin1) > WLEFT(wwin2))
629 return -1;
630 else if (WLEFT(wwin1) < WLEFT(wwin2))
631 return 1;
632 else
633 return 0;
637 static int
638 compareWRight(const void *a, const void *b)
640 WWindow *wwin1 = *(WWindow**)a;
641 WWindow *wwin2 = *(WWindow**)b;
643 if (WRIGHT(wwin1) < WRIGHT(wwin2))
644 return -1;
645 else if (WRIGHT(wwin1) > WRIGHT(wwin2))
646 return 1;
647 else
648 return 0;
653 static int
654 compareWBottom(const void *a, const void *b)
656 WWindow *wwin1 = *(WWindow**)a;
657 WWindow *wwin2 = *(WWindow**)b;
659 if (WBOTTOM(wwin1) < WBOTTOM(wwin2))
660 return -1;
661 else if (WBOTTOM(wwin1) > WBOTTOM(wwin2))
662 return 1;
663 else
664 return 0;
668 static void
669 updateResistance(WWindow *wwin, MoveData *data, int newX, int newY)
671 int i;
672 int newX2 = newX + data->winWidth;
673 int newY2 = newY + data->winHeight;
674 Bool ok = False;
676 if (newX < data->realX) {
677 if (data->rightIndex > 0
678 && newX < WRIGHT(data->rightList[data->rightIndex-1])) {
679 ok = True;
680 } else if (data->leftIndex <= data->count-1
681 && newX2 <= WLEFT(data->leftList[data->leftIndex])) {
682 ok = True;
684 } else if (newX > data->realX) {
685 if (data->leftIndex > 0
686 && newX2 > WLEFT(data->leftList[data->leftIndex-1])) {
687 ok = True;
688 } else if (data->rightIndex <= data->count-1
689 && newX >= WRIGHT(data->rightList[data->rightIndex])) {
690 ok = True;
694 if (!ok) {
695 if (newY < data->realY) {
696 if (data->bottomIndex > 0
697 && newY < WBOTTOM(data->bottomList[data->bottomIndex-1])) {
698 ok = True;
699 } else if (data->topIndex <= data->count-1
700 && newY2 <= WTOP(data->topList[data->topIndex])) {
701 ok = True;
703 } else if (newY > data->realY) {
704 if (data->topIndex > 0
705 && newY2 > WTOP(data->topList[data->topIndex-1])) {
706 ok = True;
707 } else if (data->bottomIndex <= data->count-1
708 && newY >= WBOTTOM(data->bottomList[data->bottomIndex])) {
709 ok = True;
714 if (!ok)
715 return;
717 /* TODO: optimize this */
718 if (data->realY < WBOTTOM(data->bottomList[0])) {
719 data->bottomIndex = 0;
721 if (data->realX < WRIGHT(data->rightList[0])) {
722 data->rightIndex = 0;
724 if ((data->realX + data->winWidth) > WLEFT(data->leftList[0])) {
725 data->leftIndex = 0;
727 if ((data->realY + data->winHeight) > WTOP(data->topList[0])) {
728 data->topIndex = 0;
730 for (i = 0; i < data->count; i++) {
731 if (data->realY > WBOTTOM(data->bottomList[i])) {
732 data->bottomIndex = i + 1;
734 if (data->realX > WRIGHT(data->rightList[i])) {
735 data->rightIndex = i + 1;
737 if ((data->realX + data->winWidth) < WLEFT(data->leftList[i])) {
738 data->leftIndex = i + 1;
740 if ((data->realY + data->winHeight) < WTOP(data->topList[i])) {
741 data->topIndex = i + 1;
747 static void
748 freeMoveData(MoveData *data)
750 if (data->topList)
751 free(data->topList);
752 if (data->leftList)
753 free(data->leftList);
754 if (data->rightList)
755 free(data->rightList);
756 if (data->bottomList)
757 free(data->bottomList);
761 static void
762 updateMoveData(WWindow *wwin, MoveData *data)
764 WScreen *scr = wwin->screen_ptr;
765 WWindow *tmp;
766 int i;
768 data->count = 0;
769 tmp = scr->focused_window;
770 while (tmp) {
771 if (tmp != wwin && scr->current_workspace == tmp->frame->workspace
772 && !tmp->flags.miniaturized
773 && !tmp->flags.hidden
774 && !tmp->flags.obscured
775 && !WFLAGP(tmp, sunken)) {
776 data->topList[data->count] = tmp;
777 data->leftList[data->count] = tmp;
778 data->rightList[data->count] = tmp;
779 data->bottomList[data->count] = tmp;
780 data->count++;
782 tmp = tmp->prev;
785 if (data->count == 0) {
786 data->topIndex = 0;
787 data->leftIndex = 0;
788 data->rightIndex = 0;
789 data->bottomIndex = 0;
790 return;
794 * order from closest to the border of the screen to farthest
796 qsort(data->topList, data->count, sizeof(WWindow**), compareWTop);
797 qsort(data->leftList, data->count, sizeof(WWindow**), compareWLeft);
798 qsort(data->rightList, data->count, sizeof(WWindow**), compareWRight);
799 qsort(data->bottomList, data->count, sizeof(WWindow**), compareWBottom);
801 /* figure the position of the window relative to the others */
803 data->topIndex = -1;
804 data->leftIndex = -1;
805 data->rightIndex = -1;
806 data->bottomIndex = -1;
808 if (WTOP(wwin) < WBOTTOM(data->bottomList[0])) {
809 data->bottomIndex = 0;
811 if (WLEFT(wwin) < WRIGHT(data->rightList[0])) {
812 data->rightIndex = 0;
814 if (WRIGHT(wwin) > WLEFT(data->leftList[0])) {
815 data->leftIndex = 0;
817 if (WBOTTOM(wwin) > WTOP(data->topList[0])) {
818 data->topIndex = 0;
820 for (i = 0; i < data->count; i++) {
821 if (WTOP(wwin) >= WBOTTOM(data->bottomList[i])) {
822 data->bottomIndex = i + 1;
824 if (WLEFT(wwin) >= WRIGHT(data->rightList[i])) {
825 data->rightIndex = i + 1;
827 if (WRIGHT(wwin) <= WLEFT(data->leftList[i])) {
828 data->leftIndex = i + 1;
830 if (WBOTTOM(wwin) <= WTOP(data->topList[i])) {
831 data->topIndex = i + 1;
837 static void
838 initMoveData(WWindow *wwin, MoveData *data)
840 int i;
841 WWindow *tmp;
843 memset(data, 0, sizeof(MoveData));
845 for (i = 0, tmp = wwin->screen_ptr->focused_window;
846 tmp != NULL;
847 tmp = tmp->prev, i++);
849 if (i > 1) {
850 data->topList = wmalloc(sizeof(WWindow*) * i);
851 data->leftList = wmalloc(sizeof(WWindow*) * i);
852 data->rightList = wmalloc(sizeof(WWindow*) * i);
853 data->bottomList = wmalloc(sizeof(WWindow*) * i);
855 updateMoveData(wwin, data);
858 data->realX = wwin->frame_x;
859 data->realY = wwin->frame_y;
860 data->calcX = wwin->frame_x;
861 data->calcY = wwin->frame_y;
863 data->winWidth = wwin->frame->core->width + 2;
864 data->winHeight = wwin->frame->core->height + 2;
868 static Bool
869 checkWorkspaceChange(WWindow *wwin, MoveData *data, Bool opaqueMove)
871 WScreen *scr = wwin->screen_ptr;
872 Bool changed = False;
874 if (data->mouseX <= 1) {
875 if (scr->current_workspace > 0) {
877 crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace - 1,
878 True);
879 changed = True;
880 data->rubCount = 0;
882 } else if (scr->current_workspace == 0 && wPreferences.ws_cycle) {
884 crossWorkspace(scr, wwin, opaqueMove, scr->workspace_count - 1,
885 True);
886 changed = True;
887 data->rubCount = 0;
889 } else if (data->mouseX >= scr->scr_width - 2) {
891 if (scr->current_workspace == scr->workspace_count - 1) {
893 if (wPreferences.ws_cycle
894 || scr->workspace_count == MAX_WORKSPACES) {
896 crossWorkspace(scr, wwin, opaqueMove, 0, False);
897 changed = True;
898 data->rubCount = 0;
900 /* if user insists on trying to go to next workspace even when
901 * it's already the last, create a new one */
902 else if (data->omouseX == data->mouseX
903 && wPreferences.ws_advance) {
905 /* detect user "rubbing" the window against the edge */
906 if (data->rubCount > 0
907 && data->omouseY - data->mouseY > MOVE_THRESHOLD) {
909 data->rubCount = -(data->rubCount + 1);
911 } else if (data->rubCount <= 0
912 && data->mouseY - data->omouseY > MOVE_THRESHOLD) {
914 data->rubCount = -data->rubCount + 1;
917 /* create a new workspace */
918 if (abs(data->rubCount) > 2) {
919 /* go to next workspace */
920 wWorkspaceNew(scr);
922 crossWorkspace(scr, wwin, opaqueMove,
923 scr->current_workspace+1, False);
924 changed = True;
925 data->rubCount = 0;
927 } else if (scr->current_workspace < scr->workspace_count) {
929 /* go to next workspace */
930 crossWorkspace(scr, wwin, opaqueMove,
931 scr->current_workspace+1, False);
932 changed = True;
933 data->rubCount = 0;
935 } else {
936 data->rubCount = 0;
939 return changed;
943 static void
944 updateWindowPosition(WWindow *wwin, MoveData *data, Bool doResistance,
945 Bool opaqueMove, int newMouseX, int newMouseY)
947 WScreen *scr = wwin->screen_ptr;
948 int dx, dy; /* how much mouse moved */
949 int winL, winR, winT, winB; /* requested new window position */
950 int newX, newY; /* actual new window position */
951 Bool hresist, vresist;
952 Bool updateIndex;
953 Bool attract;
955 hresist = False;
956 vresist = False;
958 updateIndex = False;
960 /* check the direction of the movement */
961 dx = newMouseX - data->mouseX;
962 dy = newMouseY - data->mouseY;
964 data->omouseX = data->mouseX;
965 data->omouseY = data->mouseY;
966 data->mouseX = newMouseX;
967 data->mouseY = newMouseY;
969 winL = data->calcX + dx;
970 winR = data->calcX + data->winWidth + dx;
971 winT = data->calcY + dy;
972 winB = data->calcY + data->winHeight + dy;
974 newX = data->realX;
975 newY = data->realY;
977 if (doResistance) {
978 int l_edge, r_edge;
979 int edge_l, edge_r;
980 int t_edge, b_edge;
981 int edge_t, edge_b;
982 int resist;
984 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
985 attract = wPreferences.attract;
986 /* horizontal movement: check horizontal edge resistances */
987 if (dx || dy) {
988 int i;
989 /* window is the leftmost window: check against screen edge */
990 l_edge = scr->totalUsableArea.x1;
991 r_edge = scr->totalUsableArea.x2 + resist;
992 edge_l = scr->totalUsableArea.x1 - resist;
993 edge_r = scr->totalUsableArea.x2;
995 /* 1 */
996 if ((data->rightIndex >= 0) && (data->rightIndex <= data->count)) {
997 WWindow *looprw;
999 for (i = data->rightIndex - 1; i >= 0; i--) {
1000 looprw = data->rightList[i];
1001 if (!(data->realY > WBOTTOM(looprw)
1002 || (data->realY + data->winHeight) < WTOP(looprw))) {
1003 if (attract
1004 || ((data->realX < (WRIGHT(looprw) + 2)) && dx < 0)) {
1005 l_edge = WRIGHT(looprw) + 1;
1006 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1008 break;
1012 if (attract) {
1013 for (i = data->rightIndex; i < data->count; i++) {
1014 looprw = data->rightList[i];
1015 if(!(data->realY > WBOTTOM(looprw)
1016 || (data->realY + data->winHeight) < WTOP(looprw))) {
1017 r_edge = WRIGHT(looprw) + 1;
1018 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1019 break;
1025 if ((data->leftIndex >= 0) && (data->leftIndex <= data->count)) {
1026 WWindow *looprw;
1028 for (i = data->leftIndex - 1; i >= 0; i--) {
1029 looprw = data->leftList[i];
1030 if (!(data->realY > WBOTTOM(looprw)
1031 || (data->realY + data->winHeight) < WTOP(looprw))) {
1032 if (attract
1033 || (((data->realX + data->winWidth) > (WLEFT(looprw) - 1)) && dx > 0)) {
1034 edge_r = WLEFT(looprw);
1035 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1037 break;
1041 if (attract)
1042 for (i = data->leftIndex; i < data->count; i++) {
1043 looprw = data->leftList[i];
1044 if(!(data->realY > WBOTTOM(looprw)
1045 || (data->realY + data->winHeight) < WTOP(looprw))) {
1046 edge_l = WLEFT(looprw);
1047 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1048 break;
1054 printf("%d %d\n",winL,winR);
1055 printf("l_ %d r_ %d _l %d _r %d\n",l_edge,r_edge,edge_l,edge_r);
1058 if ((winL - l_edge) < (r_edge - winL)) {
1059 if (resist > 0) {
1060 if ((attract && winL <= l_edge + resist && winL >= l_edge - resist)
1061 || (dx < 0 && winL <= l_edge && winL >= l_edge - resist)) {
1062 newX = l_edge;
1063 hresist = True;
1066 } else {
1067 if (resist > 0 && attract && winL >= r_edge - resist && winL <= r_edge + resist) {
1068 newX = r_edge;
1069 hresist = True;
1073 if ((winR - edge_l) < (edge_r - winR)) {
1074 if (resist > 0 && attract && winR <= edge_l + resist && winR >= edge_l - resist) {
1075 newX = edge_l - data->winWidth;
1076 hresist = True;
1078 } else {
1079 if (resist > 0) {
1080 if ((attract && winR >= edge_r - resist && winR <= edge_r + resist)
1081 || (dx > 0 && winR >= edge_r && winR <= edge_r + resist)) {
1082 newX = edge_r - data->winWidth;
1083 hresist = True;
1088 /* VeRT */
1089 t_edge = scr->totalUsableArea.y1;
1090 b_edge = scr->totalUsableArea.y2 + resist;
1091 edge_t = scr->totalUsableArea.y1 - resist;
1092 edge_b = scr->totalUsableArea.y2;
1094 if ((data->bottomIndex >= 0) && (data->bottomIndex <= data->count)) {
1095 WWindow *looprw;
1097 for (i = data->bottomIndex - 1; i >= 0; i--) {
1098 looprw = data->bottomList[i];
1099 if (!(data->realX > WRIGHT(looprw)
1100 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1101 if (attract
1102 || ((data->realY < (WBOTTOM(looprw) + 2)) && dy < 0)) {
1103 t_edge = WBOTTOM(looprw) + 1;
1104 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1106 break;
1110 if (attract) {
1111 for (i = data->bottomIndex; i < data->count; i++) {
1112 looprw = data->bottomList[i];
1113 if(!(data->realX > WRIGHT(looprw)
1114 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1115 b_edge = WBOTTOM(looprw) + 1;
1116 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1117 break;
1123 if ((data->topIndex >= 0) && (data->topIndex <= data->count)) {
1124 WWindow *looprw;
1126 for (i = data->topIndex - 1; i >= 0; i--) {
1127 looprw = data->topList[i];
1128 if (!(data->realX > WRIGHT(looprw)
1129 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1130 if (attract
1131 || (((data->realY + data->winHeight) > (WTOP(looprw) - 1)) && dy > 0)) {
1132 edge_b = WTOP(looprw);
1133 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1135 break;
1139 if (attract)
1140 for (i = data->topIndex; i < data->count; i++) {
1141 looprw = data->topList[i];
1142 if(!(data->realX > WRIGHT(looprw)
1143 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1144 edge_t = WTOP(looprw);
1145 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1146 break;
1151 if ((winT - t_edge) < (b_edge - winT)) {
1152 if (resist > 0) {
1153 if ((attract && winT <= t_edge + resist && winT >= t_edge - resist)
1154 || (dy < 0 && winT <= t_edge && winT >= t_edge - resist)) {
1155 newY = t_edge;
1156 vresist = True;
1160 else {
1161 if (resist > 0 && attract && winT >= b_edge - resist && winT <= b_edge + resist) {
1162 newY = b_edge;
1163 vresist = True;
1167 if ((winB - edge_t) < (edge_b - winB)) {
1168 if (resist > 0 && attract && winB <= edge_t + resist && winB >= edge_t - resist) {
1169 newY = edge_t - data->winHeight;
1170 vresist = True;
1173 else {
1174 if (resist > 0) {
1175 if ((attract && winB >= edge_b - resist && winB <= edge_b + resist)
1176 || (dy > 0 && winB >= edge_b && winB <= edge_b + resist)) {
1177 newY = edge_b - data->winHeight;
1178 vresist = True;
1183 /* END VeRT */
1187 /* update window position */
1188 data->calcX += dx;
1189 data->calcY += dy;
1191 if (((dx > 0 && data->calcX - data->realX > 0)
1192 || (dx < 0 && data->calcX - data->realX < 0)) && !hresist)
1193 newX = data->calcX;
1195 if (((dy > 0 && data->calcY - data->realY > 0)
1196 || (dy < 0 && data->calcY - data->realY < 0)) && !vresist)
1197 newY = data->calcY;
1199 if (data->realX != newX || data->realY != newY) {
1201 if (wPreferences.move_display == WDIS_NEW
1202 && !scr->selected_windows) {
1203 showPosition(wwin, data->realX, data->realY);
1205 if (opaqueMove) {
1206 doWindowMove(wwin, scr->selected_windows,
1207 newX - wwin->frame_x,
1208 newY - wwin->frame_y);
1209 } else {
1210 /* erase frames */
1211 drawFrames(wwin, scr->selected_windows,
1212 data->realX - wwin->frame_x,
1213 data->realY - wwin->frame_y);
1216 if (!scr->selected_windows
1217 && wPreferences.move_display == WDIS_FRAME_CENTER) {
1219 moveGeometryDisplayCentered(scr, newX + data->winWidth/2,
1220 newY + data->winHeight/2);
1223 if (!opaqueMove) {
1224 /* draw frames */
1225 drawFrames(wwin, scr->selected_windows,
1226 newX - wwin->frame_x,
1227 newY - wwin->frame_y);
1230 if (!scr->selected_windows) {
1231 showPosition(wwin, newX, newY);
1236 /* recalc relative window position */
1237 if (doResistance && (data->realX != newX || data->realY != newY)) {
1238 updateResistance(wwin, data, newX, newY);
1241 data->realX = newX;
1242 data->realY = newY;
1246 #define _KS KEY_CONTROL_WINDOW_WEIGHT
1249 wKeyboardMoveResizeWindow(WWindow *wwin)
1251 WScreen *scr = wwin->screen_ptr;
1252 Window root = scr->root_win;
1253 XEvent event;
1254 int w = wwin->frame->core->width;
1255 int h = wwin->frame->core->height;
1256 int scr_width = wwin->screen_ptr->scr_width;
1257 int scr_height = wwin->screen_ptr->scr_height;
1258 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1259 int src_x = wwin->frame_x;
1260 int src_y = wwin->frame_y;
1261 int done,off_x,off_y,ww,wh;
1262 int kspeed = _KS;
1263 Time lastTime = 0;
1264 KeySym keysym=NoSymbol;
1265 int moment=0;
1266 KeyCode shiftl,shiftr,ctrll,ctrlmode;
1268 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1269 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1270 ctrll = XKeysymToKeycode(dpy, XK_Control_L);
1271 ctrlmode=done=off_x=off_y=0;
1273 XSync(dpy, False);
1274 wusleep(10000);
1275 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1277 if (!wwin->flags.selected) {
1278 wUnselectWindows(scr);
1280 XGrabServer(dpy);
1281 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
1282 |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
1283 GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime);
1285 if (wwin->flags.shaded || scr->selected_windows) {
1286 if(scr->selected_windows)
1287 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1288 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1289 if(!scr->selected_windows)
1290 mapPositionDisplay(wwin, src_x, src_y, w, h);
1291 } else {
1292 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1294 ww=w;
1295 wh=h;
1296 while(1) {
1298 looper.ox=off_x;
1299 looper.oy=off_y;
1301 WMMaskEvent(dpy, KeyPressMask | ButtonReleaseMask
1302 | ButtonPressMask | ExposureMask, &event);
1303 if (wwin->flags.shaded || scr->selected_windows) {
1304 if(scr->selected_windows)
1305 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1306 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1307 /*** I HATE EDGE RESISTANCE - ]d ***/
1309 else {
1310 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
1313 if(ctrlmode)
1314 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
1316 XUngrabServer(dpy);
1317 XSync(dpy, False);
1319 switch (event.type) {
1320 case KeyPress:
1321 /* accelerate */
1322 if (event.xkey.time - lastTime > 50) {
1323 kspeed/=(1 + (event.xkey.time - lastTime)/100);
1324 } else {
1325 if (kspeed < 20) {
1326 kspeed++;
1329 if (kspeed < _KS) kspeed = _KS;
1330 lastTime = event.xkey.time;
1332 if (event.xkey.state & ControlMask && !wwin->flags.shaded) {
1333 ctrlmode=1;
1334 wUnselectWindows(scr);
1336 else {
1337 ctrlmode=0;
1339 if (event.xkey.keycode == shiftl || event.xkey.keycode == shiftr) {
1340 if (ctrlmode)
1341 cycleGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh, 0);
1342 else
1343 cyclePositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
1345 else {
1347 keysym = XLookupKeysym(&event.xkey, 0);
1348 switch (keysym) {
1349 case XK_Return:
1350 done=2;
1351 break;
1352 case XK_Escape:
1353 done=1;
1354 break;
1355 case XK_Up:
1356 case XK_KP_Up:
1357 case XK_k:
1358 if (ctrlmode){
1359 if (moment != UP)
1360 h = wh;
1361 h-=kspeed;
1362 moment = UP;
1363 if (h < 1) h = 1;
1365 else off_y-=kspeed;
1366 break;
1367 case XK_Down:
1368 case XK_KP_Down:
1369 case XK_j:
1370 if (ctrlmode){
1371 if (moment != DOWN)
1372 h = wh;
1373 h+=kspeed;
1374 moment = DOWN;
1376 else off_y+=kspeed;
1377 break;
1378 case XK_Left:
1379 case XK_KP_Left:
1380 case XK_h:
1381 if (ctrlmode) {
1382 if (moment != LEFT)
1383 w = ww;
1384 w-=kspeed;
1385 if (w < 1) w = 1;
1386 moment = LEFT;
1388 else off_x-=kspeed;
1389 break;
1390 case XK_Right:
1391 case XK_KP_Right:
1392 case XK_l:
1393 if (ctrlmode) {
1394 if (moment != RIGHT)
1395 w = ww;
1396 w+=kspeed;
1397 moment = RIGHT;
1399 else off_x+=kspeed;
1400 break;
1403 ww=w;wh=h;
1404 wh-=vert_border;
1405 wWindowConstrainSize(wwin, &ww, &wh);
1406 wh+=vert_border;
1408 if (wPreferences.ws_cycle){
1409 if (src_x + off_x + ww < 20){
1410 if(!scr->current_workspace) {
1411 wWorkspaceChange(scr, scr->workspace_count-1);
1413 else wWorkspaceChange(scr, scr->current_workspace-1);
1414 off_x += scr_width;
1416 else if (src_x + off_x + 20 > scr_width){
1417 if(scr->current_workspace == scr->workspace_count-1) {
1418 wWorkspaceChange(scr, 0);
1420 else wWorkspaceChange(scr, scr->current_workspace+1);
1421 off_x -= scr_width;
1424 else {
1425 if (src_x + off_x + ww < 20)
1426 off_x = 20 - ww - src_x;
1427 else if (src_x + off_x + 20 > scr_width)
1428 off_x = scr_width - 20 - src_x;
1431 if (src_y + off_y + wh < 20) {
1432 off_y = 20 - wh - src_y;
1434 else if (src_y + off_y + 20 > scr_height) {
1435 off_y = scr_height - 20 - src_y;
1438 break;
1439 case ButtonPress:
1440 case ButtonRelease:
1441 done=1;
1442 break;
1443 default:
1444 WMHandleEvent(&event);
1445 break;
1448 XGrabServer(dpy);
1449 /*xxx*/
1451 if (wwin->flags.shaded && !scr->selected_windows){
1452 moveGeometryDisplayCentered(scr, src_x+off_x + w/2, src_y+off_y + h/2);
1454 else {
1455 if(ctrlmode){
1456 unmapPositionDisplay(wwin);
1457 mapGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
1459 else if(!scr->selected_windows){
1460 unmapGeometryDisplay(wwin);
1461 mapPositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
1465 if (wwin->flags.shaded || scr->selected_windows) {
1466 if(scr->selected_windows)
1467 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1468 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1470 else {
1471 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
1475 if(ctrlmode){
1476 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
1478 else if(!scr->selected_windows)
1479 showPosition(wwin, src_x+off_x, src_y+off_y);
1480 /**/
1482 if(done){
1483 scr->keymove_tick=0;
1485 WMDeleteTimerWithClientData(&looper);
1487 if (wwin->flags.shaded || scr->selected_windows) {
1488 if(scr->selected_windows)
1489 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1490 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1492 else {
1493 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
1496 if(ctrlmode){
1497 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
1498 unmapGeometryDisplay(wwin);
1500 else
1501 unmapPositionDisplay(wwin);
1502 XUngrabKeyboard(dpy, CurrentTime);
1503 XUngrabPointer(dpy, CurrentTime);
1504 XUngrabServer(dpy);
1506 if(done==2) {
1507 if (wwin->flags.shaded || scr->selected_windows) {
1508 if (!scr->selected_windows) {
1509 wWindowMove(wwin, src_x+off_x, src_y+off_y);
1510 wWindowSynthConfigureNotify(wwin);
1511 } else {
1512 int i;
1513 WMBag *bag = scr->selected_windows;
1514 doWindowMove(wwin,scr->selected_windows,off_x,off_y);
1515 for (i = 0; i < WMGetBagItemCount(bag); i++) {
1516 wWindowSynthConfigureNotify(WMGetFromBag(bag, i));
1519 } else {
1520 if (wwin->client.width != ww)
1521 wwin->flags.user_changed_width = 1;
1523 if (wwin->client.height != wh - vert_border)
1524 wwin->flags.user_changed_height = 1;
1526 wWindowConfigure(wwin, src_x+off_x, src_y+off_y,
1527 ww, wh - vert_border);
1528 wWindowSynthConfigureNotify(wwin);
1530 wWindowChangeWorkspace(wwin, scr->current_workspace);
1531 wSetFocusTo(scr, wwin);
1533 return 1;
1540 *----------------------------------------------------------------------
1541 * wMouseMoveWindow--
1542 * Move the named window and the other selected ones (if any),
1543 * interactively. Also shows the position of the window, if only one
1544 * window is being moved.
1545 * If the window is not on the selected window list, the selected
1546 * windows are deselected.
1547 * If shift is pressed during the operation, the position display
1548 * is changed to another type.
1550 * Returns:
1551 * True if the window was moved, False otherwise.
1553 * Side effects:
1554 * The window(s) position is changed, and the client(s) are
1555 * notified about that.
1556 * The position display configuration may be changed.
1557 *----------------------------------------------------------------------
1560 wMouseMoveWindow(WWindow *wwin, XEvent *ev)
1562 WScreen *scr = wwin->screen_ptr;
1563 XEvent event;
1564 Window root = scr->root_win;
1565 KeyCode shiftl, shiftr;
1566 Bool done = False;
1567 int started = 0;
1568 int warped = 0;
1569 /* This needs not to change while moving, else bad things can happen */
1570 int opaqueMove = wPreferences.opaque_move;
1571 MoveData moveData;
1572 #ifdef GHOST_WINDOW_MOVE
1573 RImage *rimg;
1575 rimg = InitGhostWindowMove(scr);
1576 #endif
1579 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1580 XSetWindowAttributes attr;
1582 attr.save_under = True;
1583 XChangeWindowAttributes(dpy, wwin->frame->core->window,
1584 CWSaveUnder, &attr);
1588 initMoveData(wwin, &moveData);
1590 moveData.mouseX = ev->xmotion.x_root;
1591 moveData.mouseY = ev->xmotion.y_root;
1593 if (!wwin->flags.selected) {
1594 /* this window is not selected, unselect others and move only wwin */
1595 wUnselectWindows(scr);
1597 #ifdef DEBUG
1598 puts("Moving window");
1599 #endif
1600 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1601 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1602 while (!done) {
1603 if (warped) {
1604 int junk;
1605 Window junkw;
1607 /* XWarpPointer() doesn't seem to generate Motion events, so
1608 we've got to simulate them */
1609 XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
1610 &event.xmotion.y_root, &junk, &junk,
1611 (unsigned *) &junk);
1612 } else {
1613 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
1614 | ButtonReleaseMask | ButtonPressMask | ExposureMask,
1615 &event);
1617 if (event.type == MotionNotify) {
1618 /* compress MotionNotify events */
1619 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
1620 if (!checkMouseSamplingRate(&event))
1621 continue;
1624 switch (event.type) {
1625 case KeyPress:
1626 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1627 && started && !scr->selected_windows) {
1629 if (!opaqueMove) {
1630 drawFrames(wwin, scr->selected_windows,
1631 moveData.realX - wwin->frame_x,
1632 moveData.realY - wwin->frame_y);
1635 if (wPreferences.move_display == WDIS_NEW
1636 && !scr->selected_windows) {
1637 showPosition(wwin, moveData.realX, moveData.realY);
1638 XUngrabServer(dpy);
1640 cyclePositionDisplay(wwin, moveData.realX, moveData.realY,
1641 moveData.winWidth, moveData.winHeight);
1643 if (wPreferences.move_display == WDIS_NEW
1644 && !scr->selected_windows) {
1645 XGrabServer(dpy);
1646 showPosition(wwin, moveData.realX, moveData.realY);
1649 if (!opaqueMove) {
1650 drawFrames(wwin, scr->selected_windows,
1651 moveData.realX - wwin->frame_x,
1652 moveData.realY - wwin->frame_y);
1655 break;
1657 case MotionNotify:
1658 if (started) {
1659 updateWindowPosition(wwin, &moveData,
1660 scr->selected_windows == NULL
1661 && wPreferences.edge_resistance > 0,
1662 opaqueMove,
1663 event.xmotion.x_root,
1664 event.xmotion.y_root);
1666 if (!warped && !wPreferences.no_autowrap) {
1667 int oldWorkspace = scr->current_workspace;
1669 if (wPreferences.move_display == WDIS_NEW
1670 && !scr->selected_windows) {
1671 showPosition(wwin, moveData.realX, moveData.realY);
1672 XUngrabServer(dpy);
1674 if (!opaqueMove) {
1675 drawFrames(wwin, scr->selected_windows,
1676 moveData.realX - wwin->frame_x,
1677 moveData.realY - wwin->frame_y);
1679 if (checkWorkspaceChange(wwin, &moveData, opaqueMove)) {
1680 if (scr->current_workspace != oldWorkspace
1681 && wPreferences.edge_resistance > 0
1682 && scr->selected_windows == NULL)
1683 updateMoveData(wwin, &moveData);
1684 warped = 1;
1686 if (!opaqueMove) {
1687 drawFrames(wwin, scr->selected_windows,
1688 moveData.realX - wwin->frame_x,
1689 moveData.realY - wwin->frame_y);
1691 if (wPreferences.move_display == WDIS_NEW
1692 && !scr->selected_windows) {
1693 XSync(dpy, False);
1694 showPosition(wwin, moveData.realX, moveData.realY);
1695 XGrabServer(dpy);
1697 } else {
1698 warped = 0;
1700 } else if (abs(ev->xmotion.x_root - event.xmotion.x_root) >= MOVE_THRESHOLD
1701 || abs(ev->xmotion.y_root - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1703 XChangeActivePointerGrab(dpy, ButtonMotionMask
1704 | ButtonReleaseMask | ButtonPressMask,
1705 wCursor[WCUR_MOVE], CurrentTime);
1706 started = 1;
1707 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
1708 CurrentTime);
1710 if (!scr->selected_windows)
1711 mapPositionDisplay(wwin, moveData.realX, moveData.realY,
1712 moveData.winWidth, moveData.winHeight);
1714 if (started && !opaqueMove)
1715 drawFrames(wwin, scr->selected_windows, 0, 0);
1717 if (!opaqueMove || (wPreferences.move_display==WDIS_NEW
1718 && !scr->selected_windows)) {
1719 XGrabServer(dpy);
1720 if (wPreferences.move_display==WDIS_NEW)
1721 showPosition(wwin, moveData.realX, moveData.realY);
1724 break;
1726 case ButtonPress:
1727 break;
1729 case ButtonRelease:
1730 if (event.xbutton.button != ev->xbutton.button)
1731 break;
1733 if (started) {
1734 if (!opaqueMove) {
1735 drawFrames(wwin, scr->selected_windows,
1736 moveData.realX - wwin->frame_x,
1737 moveData.realY - wwin->frame_y);
1738 XSync(dpy, 0);
1739 doWindowMove(wwin, scr->selected_windows,
1740 moveData.realX - wwin->frame_x,
1741 moveData.realY - wwin->frame_y);
1743 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
1744 wWindowSynthConfigureNotify(wwin);
1745 #endif
1746 XUngrabKeyboard(dpy, CurrentTime);
1747 XUngrabServer(dpy);
1748 if (!opaqueMove) {
1749 wWindowChangeWorkspace(wwin, scr->current_workspace);
1750 wSetFocusTo(scr, wwin);
1752 if (wPreferences.move_display == WDIS_NEW)
1753 showPosition(wwin, moveData.realX, moveData.realY);
1755 if (!scr->selected_windows) {
1756 /* get rid of the geometry window */
1757 unmapPositionDisplay(wwin);
1760 #ifdef DEBUG
1761 puts("End move window");
1762 #endif
1763 done = True;
1764 break;
1766 default:
1767 if (started && !opaqueMove) {
1768 drawFrames(wwin, scr->selected_windows,
1769 moveData.realX - wwin->frame_x,
1770 moveData.realY - wwin->frame_y);
1771 XUngrabServer(dpy);
1772 WMHandleEvent(&event);
1773 XSync(dpy, False);
1774 XGrabServer(dpy);
1775 drawFrames(wwin, scr->selected_windows,
1776 moveData.realX - wwin->frame_x,
1777 moveData.realY - wwin->frame_y);
1778 } else {
1779 WMHandleEvent(&event);
1781 break;
1785 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1786 XSetWindowAttributes attr;
1789 attr.save_under = False;
1790 XChangeWindowAttributes(dpy, wwin->frame->core->window,
1791 CWSaveUnder, &attr);
1795 freeMoveData(&moveData);
1797 return started;
1801 #define RESIZEBAR 1
1802 #define HCONSTRAIN 2
1804 static int
1805 getResizeDirection(WWindow *wwin, int x, int y, int dx, int dy,
1806 int flags)
1808 int w = wwin->frame->core->width - 1;
1809 int cw = wwin->frame->resizebar_corner_width;
1810 int dir;
1812 /* if not resizing through the resizebar */
1813 if (!(flags & RESIZEBAR)) {
1814 int xdir = (abs(x) < (wwin->client.width/2)) ? LEFT : RIGHT;
1815 int ydir = (abs(y) < (wwin->client.height/2)) ? UP : DOWN;
1816 if (abs(dx) < 2 || abs(dy) < 2) {
1817 if (abs(dy) > abs(dx))
1818 xdir = 0;
1819 else
1820 ydir = 0;
1822 return (xdir | ydir);
1825 /* window is too narrow. allow diagonal resize */
1826 if (cw * 2 >= w) {
1827 int ydir;
1829 if (flags & HCONSTRAIN)
1830 ydir = 0;
1831 else
1832 ydir = DOWN;
1833 if (x < cw)
1834 return (LEFT | ydir);
1835 else
1836 return (RIGHT | ydir);
1838 /* vertical resize */
1839 if ((x > cw) && (x < w - cw))
1840 return DOWN;
1842 if (x < cw)
1843 dir = LEFT;
1844 else
1845 dir = RIGHT;
1847 if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
1848 dir |= DOWN;
1850 return dir;
1854 void
1855 wMouseResizeWindow(WWindow *wwin, XEvent *ev)
1857 XEvent event;
1858 WScreen *scr = wwin->screen_ptr;
1859 Window root = scr->root_win;
1860 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1861 int fw = wwin->frame->core->width;
1862 int fh = wwin->frame->core->height;
1863 int fx = wwin->frame_x;
1864 int fy = wwin->frame_y;
1865 int is_resizebar = (wwin->frame->resizebar
1866 && ev->xany.window==wwin->frame->resizebar->window);
1867 int orig_x, orig_y;
1868 int started;
1869 int dw, dh;
1870 int rw = fw, rh = fh;
1871 int rx1, ry1, rx2, ry2;
1872 int res = 0;
1873 KeyCode shiftl, shiftr;
1874 int h = 0;
1875 int orig_fx = fx;
1876 int orig_fy = fy;
1877 int orig_fw = fw;
1878 int orig_fh = fh;
1880 if (wwin->flags.shaded) {
1881 wwarning("internal error: tryein");
1882 return;
1884 orig_x = ev->xbutton.x_root;
1885 orig_y = ev->xbutton.y_root;
1887 started = 0;
1888 #ifdef DEBUG
1889 puts("Resizing window");
1890 #endif
1892 wUnselectWindows(scr);
1893 rx1 = fx;
1894 rx2 = fx + fw - 1;
1895 ry1 = fy;
1896 ry2 = fy + fh - 1;
1897 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1898 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1899 if (!WFLAGP(wwin, no_titlebar))
1900 h = WMFontHeight(wwin->screen_ptr->title_font) + TITLEBAR_EXTRA_HEIGHT;
1901 else
1902 h = 0;
1903 while (1) {
1904 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask | ButtonReleaseMask
1905 | ButtonPressMask | ExposureMask, &event);
1906 if (!checkMouseSamplingRate(&event))
1907 continue;
1909 switch (event.type) {
1910 case KeyPress:
1911 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1912 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1913 && started) {
1914 drawTransparentFrame(wwin, fx, fy, fw, fh);
1915 cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
1916 drawTransparentFrame(wwin, fx, fy, fw, fh);
1918 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1919 break;
1921 case MotionNotify:
1922 if (started) {
1923 dw = 0;
1924 dh = 0;
1926 orig_fx = fx;
1927 orig_fy = fy;
1928 orig_fw = fw;
1929 orig_fh = fh;
1931 if (res & LEFT)
1932 dw = orig_x - event.xmotion.x_root;
1933 else if (res & RIGHT)
1934 dw = event.xmotion.x_root - orig_x;
1935 if (res & UP)
1936 dh = orig_y - event.xmotion.y_root;
1937 else if (res & DOWN)
1938 dh = event.xmotion.y_root - orig_y;
1940 orig_x = event.xmotion.x_root;
1941 orig_y = event.xmotion.y_root;
1943 rw += dw;
1944 rh += dh;
1945 fw = rw;
1946 fh = rh - vert_border;
1947 wWindowConstrainSize(wwin, &fw, &fh);
1948 fh += vert_border;
1949 if (res & LEFT)
1950 fx = rx2 - fw + 1;
1951 else if (res & RIGHT)
1952 fx = rx1;
1953 if (res & UP)
1954 fy = ry2 - fh + 1;
1955 else if (res & DOWN)
1956 fy = ry1;
1957 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
1958 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1959 int tx, ty;
1960 Window junkw;
1961 int flags;
1963 XTranslateCoordinates(dpy, root, wwin->frame->core->window,
1964 orig_x, orig_y, &tx, &ty, &junkw);
1966 /* check if resizing through resizebar */
1967 if (is_resizebar)
1968 flags = RESIZEBAR;
1969 else
1970 flags = 0;
1972 if (is_resizebar && ((ev->xbutton.state & ShiftMask)
1973 || abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
1974 flags |= HCONSTRAIN;
1976 res = getResizeDirection(wwin, tx, ty,
1977 orig_x - event.xmotion.x_root,
1978 orig_y - event.xmotion.y_root, flags);
1980 XChangeActivePointerGrab(dpy, ButtonMotionMask
1981 | ButtonReleaseMask | ButtonPressMask,
1982 wCursor[WCUR_RESIZE], CurrentTime);
1983 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
1984 CurrentTime);
1986 XGrabServer(dpy);
1988 /* Draw the resize frame for the first time. */
1989 mapGeometryDisplay(wwin, fx, fy, fw, fh);
1991 drawTransparentFrame(wwin, fx, fy, fw, fh);
1993 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1995 started = 1;
1997 if (started) {
1998 if (wPreferences.size_display == WDIS_FRAME_CENTER) {
1999 drawTransparentFrame(wwin, orig_fx, orig_fy,
2000 orig_fw, orig_fh);
2001 moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
2002 drawTransparentFrame(wwin, fx, fy, fw, fh);
2003 } else {
2004 drawTransparentFrame(wwin, orig_fx, orig_fy,
2005 orig_fw, orig_fh);
2006 drawTransparentFrame(wwin, fx, fy, fw, fh);
2008 if (fh != orig_fh || fw != orig_fw) {
2009 if (wPreferences.size_display == WDIS_NEW) {
2010 showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw,
2011 orig_fy + orig_fh, res);
2013 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2016 break;
2018 case ButtonPress:
2019 break;
2021 case ButtonRelease:
2022 if (event.xbutton.button != ev->xbutton.button)
2023 break;
2025 if (started) {
2026 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2028 drawTransparentFrame(wwin, fx, fy, fw, fh);
2030 XUngrabKeyboard(dpy, CurrentTime);
2031 unmapGeometryDisplay(wwin);
2032 XUngrabServer(dpy);
2034 if (wwin->client.width != fw)
2035 wwin->flags.user_changed_width = 1;
2037 if (wwin->client.height != fh - vert_border)
2038 wwin->flags.user_changed_height = 1;
2040 wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
2042 #ifdef DEBUG
2043 puts("End resize window");
2044 #endif
2045 return;
2047 default:
2048 WMHandleEvent(&event);
2053 #undef LEFT
2054 #undef RIGHT
2055 #undef HORIZONTAL
2056 #undef UP
2057 #undef DOWN
2058 #undef VERTICAL
2059 #undef HCONSTRAIN
2060 #undef RESIZEBAR
2062 void
2063 wUnselectWindows(WScreen *scr)
2065 WWindow *wwin;
2067 if (!scr->selected_windows)
2068 return;
2070 while (WMGetBagItemCount(scr->selected_windows)) {
2071 wwin = WMGetFromBag(scr->selected_windows, 0);
2072 if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
2073 wIconSelect(wwin->icon);
2075 wSelectWindow(wwin, False);
2077 WMFreeBag(scr->selected_windows);
2078 scr->selected_windows = NULL;
2081 #ifndef LITE
2082 static void
2083 selectWindowsInside(WScreen *scr, int x1, int y1, int x2, int y2)
2085 WWindow *tmpw;
2087 /* select the windows and put them in the selected window list */
2088 tmpw = scr->focused_window;
2089 while (tmpw != NULL) {
2090 if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
2091 if ((tmpw->frame->workspace == scr->current_workspace
2092 || IS_OMNIPRESENT(tmpw))
2093 && (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1)
2094 && (tmpw->frame->core->width + tmpw->frame_x <= x2)
2095 && (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
2096 wSelectWindow(tmpw, True);
2099 tmpw = tmpw->prev;
2104 void
2105 wSelectWindows(WScreen *scr, XEvent *ev)
2107 XEvent event;
2108 Window root = scr->root_win;
2109 GC gc = scr->frame_gc;
2110 int xp = ev->xbutton.x_root;
2111 int yp = ev->xbutton.y_root;
2112 int w = 0, h = 0;
2113 int x = xp, y = yp;
2115 #ifdef DEBUG
2116 puts("Selecting windows");
2117 #endif
2118 if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
2119 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
2120 GrabModeAsync, None, wCursor[WCUR_DEFAULT],
2121 CurrentTime) != Success) {
2122 return;
2124 XGrabServer(dpy);
2126 wUnselectWindows(scr);
2128 XDrawRectangle(dpy, root, gc, xp, yp, w, h);
2129 while (1) {
2130 WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask
2131 | ButtonPressMask, &event);
2133 switch (event.type) {
2134 case MotionNotify:
2135 XDrawRectangle(dpy, root, gc, x, y, w, h);
2136 x = event.xmotion.x_root;
2137 if (x < xp) {
2138 w = xp - x;
2139 } else {
2140 w = x - xp;
2141 x = xp;
2143 y = event.xmotion.y_root;
2144 if (y < yp) {
2145 h = yp - y;
2146 } else {
2147 h = y - yp;
2148 y = yp;
2150 XDrawRectangle(dpy, root, gc, x, y, w, h);
2151 break;
2153 case ButtonPress:
2154 break;
2156 case ButtonRelease:
2157 if (event.xbutton.button != ev->xbutton.button)
2158 break;
2160 XDrawRectangle(dpy, root, gc, x, y, w, h);
2161 XUngrabServer(dpy);
2162 XUngrabPointer(dpy, CurrentTime);
2163 selectWindowsInside(scr, x, y, x + w, y + h);
2165 #ifdef KWM_HINTS
2166 wKWMSelectRootRegion(scr, xp, yp, w, h,
2167 event.xbutton.state & ControlMask);
2168 #endif /* KWM_HINTS */
2170 #ifdef DEBUG
2171 puts("End window selection");
2172 #endif
2173 return;
2175 default:
2176 WMHandleEvent(&event);
2177 break;
2181 #endif /* !LITE */
2183 void
2184 InteractivePlaceWindow(WWindow *wwin, int *x_ret, int *y_ret,
2185 unsigned width, unsigned height)
2187 WScreen *scr = wwin->screen_ptr;
2188 Window root = scr->root_win;
2189 int x, y, h = 0;
2190 XEvent event;
2191 KeyCode shiftl, shiftr;
2192 Window junkw;
2193 int junk;
2195 if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
2196 GrabModeAsync, GrabModeAsync, None,
2197 wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
2198 *x_ret = 0;
2199 *y_ret = 0;
2200 return;
2202 if (!WFLAGP(wwin, no_titlebar)) {
2203 h = WMFontHeight(scr->title_font) + TITLEBAR_EXTRA_HEIGHT;
2204 height += h;
2206 if (!WFLAGP(wwin, no_resizebar)) {
2207 height += RESIZEBAR_HEIGHT;
2209 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
2210 XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk,
2211 (unsigned *) &junk);
2212 mapPositionDisplay(wwin, x - width/2, y - h/2, width, height);
2214 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2216 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
2217 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
2218 while (1) {
2219 WMMaskEvent(dpy, PointerMotionMask|ButtonPressMask|ExposureMask|KeyPressMask,
2220 &event);
2222 if (!checkMouseSamplingRate(&event))
2223 continue;
2225 switch (event.type) {
2226 case KeyPress:
2227 if ((event.xkey.keycode == shiftl)
2228 || (event.xkey.keycode == shiftr)) {
2229 drawTransparentFrame(wwin,
2230 x - width/2, y - h/2, width, height);
2231 cyclePositionDisplay(wwin,
2232 x - width/2, y - h/2, width, height);
2233 drawTransparentFrame(wwin,
2234 x - width/2, y - h/2, width, height);
2236 break;
2238 case MotionNotify:
2239 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2241 x = event.xmotion.x_root;
2242 y = event.xmotion.y_root;
2244 if (wPreferences.move_display == WDIS_FRAME_CENTER)
2245 moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
2247 showPosition(wwin, x - width/2, y - h/2);
2249 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2251 break;
2253 case ButtonPress:
2254 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2255 XSync(dpy, 0);
2256 *x_ret = x - width/2;
2257 *y_ret = y - h/2;
2258 XUngrabPointer(dpy, CurrentTime);
2259 XUngrabKeyboard(dpy, CurrentTime);
2260 /* get rid of the geometry window */
2261 unmapPositionDisplay(wwin);
2262 return;
2264 default:
2265 WMHandleEvent(&event);
2266 break;