- Check whether libXft is at least version 2.1.2 else refuse to compile.
[wmaker-crm.git] / src / moveres.c
blobeaf7bb3c0a1d9f926337577f3abe1a7bd1acb6be
1 /*
2 * Window Maker window manager
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 * USA.
22 #include "wconfig.h"
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
26 #include <X11/keysym.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
32 #include "WindowMaker.h"
33 #include "wcore.h"
34 #include "framewin.h"
35 #include "window.h"
36 #include "client.h"
37 #include "icon.h"
38 #include "dock.h"
39 #include "funcs.h"
40 #include "actions.h"
41 #include "workspace.h"
43 #include "geomview.h"
44 #include "screen.h"
45 #include "xinerama.h"
47 #include <WINGs/WINGsP.h>
50 #ifdef KWM_HINTS
51 #include "kwm.h"
52 #endif
54 /* How many different types of geometry/position
55 display thingies are there? */
56 #define NUM_DISPLAYS 5
58 #define LEFT 1
59 #define RIGHT 2
60 #define HORIZONTAL (LEFT|RIGHT)
61 #define UP 4
62 #define DOWN 8
63 #define VERTICAL (UP|DOWN)
66 /* True if window currently has a border. This also includes borderless
67 * windows which are currently selected
69 #define HAS_BORDER_WITH_SELECT(w) ((w)->flags.selected || HAS_BORDER(w))
72 /****** Global Variables ******/
73 extern Time LastTimestamp;
75 extern Cursor wCursor[WCUR_LAST];
77 extern WPreferences wPreferences;
79 extern Atom _XA_WM_PROTOCOLS;
84 *----------------------------------------------------------------------
85 * checkMouseSamplingRate-
86 * For lowering the mouse motion sampling rate for machines where
87 * it's too high (SGIs). If it returns False then the event should be
88 * ignored.
89 *----------------------------------------------------------------------
91 static Bool
92 checkMouseSamplingRate(XEvent *ev)
94 static Time previousMotion = 0;
96 if (ev->type == MotionNotify) {
97 if (ev->xmotion.time - previousMotion < DELAY_BETWEEN_MOUSE_SAMPLING) {
98 return False;
99 } else {
100 previousMotion = ev->xmotion.time;
103 return True;
109 *----------------------------------------------------------------------
110 * moveGeometryDisplayCentered
112 * routine that moves the geometry/position window on scr so it is
113 * centered over the given coordinates (x,y). Also the window position
114 * is clamped so it stays on the screen at all times.
115 *----------------------------------------------------------------------
117 static void
118 moveGeometryDisplayCentered(WScreen *scr, int x, int y)
120 unsigned int w = WMWidgetWidth(scr->gview);
121 unsigned int h = WMWidgetHeight(scr->gview);
122 int x1 = 0, y1 = 0, x2 = scr->scr_width, y2 = scr->scr_height;
124 x -= w / 2;
125 y -= h / 2;
127 /* dead area check */
128 if (scr->xine_info.count) {
129 WMRect rect;
130 int head, flags;
132 rect.pos.x = x;
133 rect.pos.y = y;
134 rect.size.width = w;
135 rect.size.height = h;
137 head = wGetRectPlacementInfo(scr, rect, &flags);
139 if (flags & (XFLAG_DEAD | XFLAG_PARTIAL)) {
140 rect = wGetRectForHead(scr, head);
141 x1 = rect.pos.x;
142 y1 = rect.pos.y;
143 x2 = x1 + rect.size.width;
144 y2 = y1 + rect.size.height;
148 if (x < x1 + 1)
149 x = x1 + 1;
150 else if (x > (x2 - w))
151 x = x2 - w;
153 if (y < y1 + 1)
154 y = y1 + 1;
155 else if (y > (y2 - h))
156 y = y2 - h;
159 WMMoveWidget(scr->gview, x, y);
163 static void
164 showPosition(WWindow *wwin, int x, int y)
166 WScreen *scr = wwin->screen_ptr;
168 if (wPreferences.move_display == WDIS_NEW) {
169 #if 0
170 int width = wwin->frame->core->width;
171 int height = wwin->frame->core->height;
173 GC lgc = scr->line_gc;
174 XSetForeground(dpy, lgc, scr->line_pixel);
175 sprintf(num, "%i", x);
177 XDrawLine(dpy, scr->root_win, lgc, 0, y-1, scr->scr_width, y-1);
178 XDrawLine(dpy, scr->root_win, lgc, 0, y+height+2, scr->scr_width,
179 y+height+2);
180 XDrawLine(dpy, scr->root_win, lgc, x-1, 0, x-1, scr->scr_height);
181 XDrawLine(dpy, scr->root_win, lgc, x+width+2, 0, x+width+2,
182 scr->scr_height);
183 #endif
184 } else {
185 #ifdef VIRTUAL_DESKTOP
186 WSetGeometryViewShownPosition(scr->gview,
187 x + scr->workspaces[scr->current_workspace]->view_x,
188 y + scr->workspaces[scr->current_workspace]->view_y);
189 #else
190 WSetGeometryViewShownPosition(scr->gview, x, y);
191 #endif
196 static void
197 cyclePositionDisplay(WWindow *wwin, int x, int y, int w, int h)
199 WScreen *scr = wwin->screen_ptr;
200 WMRect rect;
202 wPreferences.move_display++;
203 wPreferences.move_display %= NUM_DISPLAYS;
205 if (wPreferences.move_display == WDIS_NEW) {
206 wPreferences.move_display++;
207 wPreferences.move_display %= NUM_DISPLAYS;
210 if (wPreferences.move_display == WDIS_NONE) {
211 WMUnmapWidget(scr->gview);
212 } else {
213 if (wPreferences.move_display == WDIS_CENTER) {
214 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
215 moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width/2,
216 rect.pos.y + rect.size.height/2);
217 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
218 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
219 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
220 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
221 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
223 WMMapWidget(scr->gview);
228 static void
229 mapPositionDisplay(WWindow *wwin, int x, int y, int w, int h)
231 WScreen *scr = wwin->screen_ptr;
232 WMRect rect;
234 if (wPreferences.move_display == WDIS_NEW
235 || wPreferences.move_display == WDIS_NONE) {
236 return;
237 } else if (wPreferences.move_display == WDIS_CENTER) {
238 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
239 moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width/2,
240 rect.pos.y + rect.size.height/2);
241 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
242 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
243 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
244 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
245 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
247 WMMapWidget(scr->gview);
248 WSetGeometryViewShownPosition(scr->gview, x, y);
252 static void
253 showGeometry(WWindow *wwin, int x1, int y1, int x2, int y2, int direction)
255 WScreen *scr = wwin->screen_ptr;
256 Window root = scr->root_win;
257 GC gc = scr->line_gc;
258 int ty, by, my, x, y, mx, s;
259 char num[16];
260 XSegment segment[4];
261 int fw, fh;
263 /* This seems necessary for some odd reason (too lazy to write x1-1 and
264 * x2-1 everywhere below in the code). But why only for x? */
265 x1--; x2--;
267 if (HAS_BORDER_WITH_SELECT(wwin)) {
268 x1 += FRAME_BORDER_WIDTH;
269 x2 += FRAME_BORDER_WIDTH;
270 y1 += FRAME_BORDER_WIDTH;
271 y2 += FRAME_BORDER_WIDTH;
274 ty = y1 + wwin->frame->top_width;
275 by = y2 - wwin->frame->bottom_width;
277 if (wPreferences.size_display == WDIS_NEW) {
278 fw = XTextWidth(scr->tech_draw_font, "8888", 4);
279 fh = scr->tech_draw_font->ascent+scr->tech_draw_font->descent;
281 XSetForeground(dpy, gc, scr->line_pixel);
283 /* vertical geometry */
284 if (((direction & LEFT) && (x2 < scr->scr_width - fw)) || (x1 < fw)) {
285 x = x2;
286 s = -15;
287 } else {
288 x = x1;
289 s = 15;
291 my = (ty + by) / 2;
293 /* top arrow & end bar */
294 segment[0].x1 = x - (s + 6); segment[0].y1 = ty;
295 segment[0].x2 = x - (s - 10); segment[0].y2 = ty;
297 /* arrowhead */
298 segment[1].x1 = x - (s - 2); segment[1].y1 = ty + 1;
299 segment[1].x2 = x - (s - 5); segment[1].y2 = ty + 7;
301 segment[2].x1 = x - (s - 2); segment[2].y1 = ty + 1;
302 segment[2].x2 = x - (s + 1); segment[2].y2 = ty + 7;
304 /* line */
305 segment[3].x1 = x - (s - 2); segment[3].y1 = ty + 1;
306 segment[3].x2 = x - (s - 2); segment[3].y2 = my - fh/2 - 1;
308 XDrawSegments(dpy, root, gc, segment, 4);
310 /* bottom arrow & end bar */
311 segment[0].y1 = by;
312 segment[0].y2 = by;
314 /* arrowhead */
315 segment[1].y1 = by - 1;
316 segment[1].y2 = by - 7;
318 segment[2].y1 = by - 1;
319 segment[2].y2 = by - 7;
321 /* line */
322 segment[3].y1 = my + fh/2 + 2;
323 segment[3].y2 = by - 1;
325 XDrawSegments(dpy, root, gc, segment, 4);
327 snprintf(num, sizeof(num), "%i", (by - ty - wwin->normal_hints->base_height) /
328 wwin->normal_hints->height_inc);
329 fw = XTextWidth(scr->tech_draw_font, num, strlen(num));
331 /* Display the height. */
332 XSetFont(dpy, gc, scr->tech_draw_font->fid);
333 XDrawString(dpy, root, gc, x - s + 3 - fw/2, my + scr->tech_draw_font->ascent - fh/2 + 1, num, strlen(num));
335 /* horizontal geometry */
336 if (y1 < 15) {
337 y = y2;
338 s = -15;
339 } else {
340 y = y1;
341 s = 15;
343 mx = x1 + (x2 - x1)/2;
344 snprintf(num, sizeof(num), "%i", (x2 - x1 - wwin->normal_hints->base_width) /
345 wwin->normal_hints->width_inc);
346 fw = XTextWidth(scr->tech_draw_font, num, strlen(num));
348 /* left arrow & end bar */
349 segment[0].x1 = x1; segment[0].y1 = y - (s + 6);
350 segment[0].x2 = x1; segment[0].y2 = y - (s - 10);
352 /* arrowhead */
353 segment[1].x1 = x1 + 7; segment[1].y1 = y - (s + 1);
354 segment[1].x2 = x1 + 1; segment[1].y2 = y - (s - 2);
356 segment[2].x1 = x1 + 1; segment[2].y1 = y - (s - 2);
357 segment[2].x2 = x1 + 7; segment[2].y2 = y - (s - 5);
359 /* line */
360 segment[3].x1 = x1 + 1; segment[3].y1 = y - (s - 2);
361 segment[3].x2 = mx - fw/2 - 2; segment[3].y2 = y - (s - 2);
363 XDrawSegments(dpy, root, gc, segment, 4);
365 /* right arrow & end bar */
366 segment[0].x1 = x2 + 1;
367 segment[0].x2 = x2 + 1;
369 /* arrowhead */
370 segment[1].x1 = x2 - 6;
371 segment[1].x2 = x2;
373 segment[2].x1 = x2;
374 segment[2].x2 = x2 - 6;
376 /* line */
377 segment[3].x1 = mx + fw/2 + 2;
378 segment[3].x2 = x2;
380 XDrawSegments(dpy, root, gc, segment, 4);
382 /* Display the width. */
383 XDrawString(dpy, root, gc, mx - fw/2 + 1, y - s + scr->tech_draw_font->ascent - fh/2 + 1, num, strlen(num));
384 } else {
385 WSetGeometryViewShownSize(scr->gview,
386 (x2 - x1 - wwin->normal_hints->base_width)
387 / wwin->normal_hints->width_inc,
388 (by - ty - wwin->normal_hints->base_height)
389 / wwin->normal_hints->height_inc);
394 static void
395 cycleGeometryDisplay(WWindow *wwin, int x, int y, int w, int h, int dir)
397 WScreen *scr = wwin->screen_ptr;
398 WMRect rect;
400 wPreferences.size_display++;
401 wPreferences.size_display %= NUM_DISPLAYS;
403 if (wPreferences.size_display == WDIS_NEW
404 || wPreferences.size_display == WDIS_NONE) {
405 WMUnmapWidget(scr->gview);
406 } else {
407 if (wPreferences.size_display == WDIS_CENTER) {
408 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
409 moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width/2,
410 rect.pos.y + rect.size.height/2);
411 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
412 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
413 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
414 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
415 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
417 WMMapWidget(scr->gview);
418 showGeometry(wwin, x, y, x + w, y + h, dir);
423 static void
424 mapGeometryDisplay(WWindow *wwin, int x, int y, int w, int h)
426 WScreen *scr = wwin->screen_ptr;
427 WMRect rect;
429 if (wPreferences.size_display == WDIS_NEW
430 || wPreferences.size_display == WDIS_NONE)
431 return;
433 if (wPreferences.size_display == WDIS_CENTER) {
434 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
435 moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width/2,
436 rect.pos.y + rect.size.height/2);
437 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
438 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
439 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
440 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
441 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
443 WMMapWidget(scr->gview);
444 showGeometry(wwin, x, y, x + w, y + h, 0);
449 static void
450 doWindowMove(WWindow *wwin, WMArray *array, int dx, int dy)
452 WWindow *tmpw;
453 WScreen *scr = wwin->screen_ptr;
454 int x, y;
456 if (!array || !WMGetArrayItemCount(array)) {
457 wWindowMove(wwin, wwin->frame_x + dx, wwin->frame_y + dy);
458 } else {
459 WMArrayIterator iter;
461 WM_ITERATE_ARRAY(array, tmpw, iter) {
462 x = tmpw->frame_x + dx;
463 y = tmpw->frame_y + dy;
465 #if 1 /* XXX: with xinerama patch was #if 0, check this */
466 /* don't let windows become unreachable */
468 if (x + (int)tmpw->frame->core->width < 20)
469 x = 20 - (int)tmpw->frame->core->width;
470 else if (x + 20 > scr->scr_width)
471 x = scr->scr_width - 20;
473 if (y + (int)tmpw->frame->core->height < 20)
474 y = 20 - (int)tmpw->frame->core->height;
475 else if (y + 20 > scr->scr_height)
476 y = scr->scr_height - 20;
477 #else
478 wScreenBringInside(scr, &x, &y,
479 (int)tmpw->frame->core->width,
480 (int)tmpw->frame->core->height);
481 #endif
483 wWindowMove(tmpw, x, y);
489 static void
490 drawTransparentFrame(WWindow *wwin, int x, int y, int width, int height)
492 Window root = wwin->screen_ptr->root_win;
493 GC gc = wwin->screen_ptr->frame_gc;
494 int h = 0;
495 int bottom = 0;
497 if (HAS_BORDER_WITH_SELECT(wwin)) {
498 x += FRAME_BORDER_WIDTH;
499 y += FRAME_BORDER_WIDTH;
502 if (HAS_TITLEBAR(wwin) && !wwin->flags.shaded) {
503 h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
505 if (HAS_RESIZEBAR(wwin) && !wwin->flags.shaded) {
506 /* Can't use wwin-frame->bottom_width because, in some cases
507 (e.g. interactive placement), frame does not point to anything. */
508 bottom = RESIZEBAR_HEIGHT;
510 XDrawRectangle(dpy, root, gc, x - 1, y - 1, width + 1, height + 1);
512 if (h > 0) {
513 XDrawLine(dpy, root, gc, x, y + h - 1, x + width, y + h - 1);
515 if (bottom > 0) {
516 XDrawLine(dpy, root, gc, x, y + height - bottom,
517 x + width, y + height - bottom);
522 static void
523 drawFrames(WWindow *wwin, WMArray *array, int dx, int dy)
525 WWindow *tmpw;
526 int scr_width = wwin->screen_ptr->scr_width;
527 int scr_height = wwin->screen_ptr->scr_height;
528 int x, y;
530 if (!array) {
532 x = wwin->frame_x + dx;
533 y = wwin->frame_y + dy;
535 drawTransparentFrame(wwin, x, y,
536 wwin->frame->core->width,
537 wwin->frame->core->height);
539 } else {
540 WMArrayIterator iter;
542 WM_ITERATE_ARRAY(array, tmpw, iter) {
543 x = tmpw->frame_x + dx;
544 y = tmpw->frame_y + dy;
546 /* don't let windows become unreachable */
547 #if 1 /* XXX: was 0 in XINERAMA patch, check */
548 if (x + (int)tmpw->frame->core->width < 20)
549 x = 20 - (int)tmpw->frame->core->width;
550 else if (x + 20 > scr_width)
551 x = scr_width - 20;
553 if (y + (int)tmpw->frame->core->height < 20)
554 y = 20 - (int)tmpw->frame->core->height;
555 else if (y + 20 > scr_height)
556 y = scr_height - 20;
558 #else
559 wScreenBringInside(wwin->screen_ptr, &x, &y,
560 (int)tmpw->frame->core->width,
561 (int)tmpw->frame->core->height);
562 #endif
564 drawTransparentFrame(tmpw, x, y, tmpw->frame->core->width,
565 tmpw->frame->core->height);
572 static void
573 flushMotion()
575 XEvent ev;
577 XSync(dpy, False);
578 while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
582 static void
583 crossWorkspace(WScreen *scr, WWindow *wwin, int opaque_move,
584 int new_workspace, int rewind)
586 /* do not let window be unmapped */
587 if (opaque_move) {
588 wwin->flags.changing_workspace = 1;
589 wWindowChangeWorkspace(wwin, new_workspace);
591 /* go to new workspace */
592 wWorkspaceChange(scr, new_workspace);
594 wwin->flags.changing_workspace = 0;
596 if (rewind)
597 XWarpPointer(dpy, None, None, 0, 0, 0, 0, scr->scr_width - 20, 0);
598 else
599 XWarpPointer(dpy, None, None, 0, 0, 0, 0, -(scr->scr_width - 20), 0);
601 flushMotion();
603 if (!opaque_move) {
604 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
605 |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
606 GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
613 typedef struct {
614 /* arrays of WWindows sorted by the respective border position */
615 WWindow **topList; /* top border */
616 WWindow **leftList; /* left border */
617 WWindow **rightList; /* right border */
618 WWindow **bottomList; /* bottom border */
619 int count;
621 /* index of window in the above lists indicating the relative position
622 * of the window with the others */
623 int topIndex;
624 int leftIndex;
625 int rightIndex;
626 int bottomIndex;
628 int rubCount; /* for workspace switching */
630 int winWidth, winHeight; /* width/height of the window */
631 int realX, realY; /* actual position of the window */
632 int calcX, calcY; /* calculated position of window */
633 int omouseX, omouseY; /* old mouse position */
634 int mouseX, mouseY; /* last known position of the pointer */
635 } MoveData;
637 #define WTOP(w) (w)->frame_y
638 #define WLEFT(w) (w)->frame_x
639 #define WRIGHT(w) ((w)->frame_x + (int)(w)->frame->core->width - 1 + \
640 (HAS_BORDER_WITH_SELECT(w) ? 2*FRAME_BORDER_WIDTH : 0))
641 #define WBOTTOM(w) ((w)->frame_y + (int)(w)->frame->core->height - 1 + \
642 (HAS_BORDER_WITH_SELECT(w) ? 2*FRAME_BORDER_WIDTH : 0))
644 static int
645 compareWTop(const void *a, const void *b)
647 WWindow *wwin1 = *(WWindow**)a;
648 WWindow *wwin2 = *(WWindow**)b;
650 if (WTOP(wwin1) > WTOP(wwin2))
651 return -1;
652 else if (WTOP(wwin1) < WTOP(wwin2))
653 return 1;
654 else
655 return 0;
659 static int
660 compareWLeft(const void *a, const void *b)
662 WWindow *wwin1 = *(WWindow**)a;
663 WWindow *wwin2 = *(WWindow**)b;
665 if (WLEFT(wwin1) > WLEFT(wwin2))
666 return -1;
667 else if (WLEFT(wwin1) < WLEFT(wwin2))
668 return 1;
669 else
670 return 0;
674 static int
675 compareWRight(const void *a, const void *b)
677 WWindow *wwin1 = *(WWindow**)a;
678 WWindow *wwin2 = *(WWindow**)b;
680 if (WRIGHT(wwin1) < WRIGHT(wwin2))
681 return -1;
682 else if (WRIGHT(wwin1) > WRIGHT(wwin2))
683 return 1;
684 else
685 return 0;
690 static int
691 compareWBottom(const void *a, const void *b)
693 WWindow *wwin1 = *(WWindow**)a;
694 WWindow *wwin2 = *(WWindow**)b;
696 if (WBOTTOM(wwin1) < WBOTTOM(wwin2))
697 return -1;
698 else if (WBOTTOM(wwin1) > WBOTTOM(wwin2))
699 return 1;
700 else
701 return 0;
705 static void
706 updateResistance(WWindow *wwin, MoveData *data, int newX, int newY)
708 int i;
709 int newX2 = newX + data->winWidth;
710 int newY2 = newY + data->winHeight;
711 Bool ok = False;
713 if (newX < data->realX) {
714 if (data->rightIndex > 0
715 && newX < WRIGHT(data->rightList[data->rightIndex-1])) {
716 ok = True;
717 } else if (data->leftIndex <= data->count-1
718 && newX2 <= WLEFT(data->leftList[data->leftIndex])) {
719 ok = True;
721 } else if (newX > data->realX) {
722 if (data->leftIndex > 0
723 && newX2 > WLEFT(data->leftList[data->leftIndex-1])) {
724 ok = True;
725 } else if (data->rightIndex <= data->count-1
726 && newX >= WRIGHT(data->rightList[data->rightIndex])) {
727 ok = True;
731 if (!ok) {
732 if (newY < data->realY) {
733 if (data->bottomIndex > 0
734 && newY < WBOTTOM(data->bottomList[data->bottomIndex-1])) {
735 ok = True;
736 } else if (data->topIndex <= data->count-1
737 && newY2 <= WTOP(data->topList[data->topIndex])) {
738 ok = True;
740 } else if (newY > data->realY) {
741 if (data->topIndex > 0
742 && newY2 > WTOP(data->topList[data->topIndex-1])) {
743 ok = True;
744 } else if (data->bottomIndex <= data->count-1
745 && newY >= WBOTTOM(data->bottomList[data->bottomIndex])) {
746 ok = True;
751 if (!ok)
752 return;
754 /* TODO: optimize this */
755 if (data->realY < WBOTTOM(data->bottomList[0])) {
756 data->bottomIndex = 0;
758 if (data->realX < WRIGHT(data->rightList[0])) {
759 data->rightIndex = 0;
761 if ((data->realX + data->winWidth) > WLEFT(data->leftList[0])) {
762 data->leftIndex = 0;
764 if ((data->realY + data->winHeight) > WTOP(data->topList[0])) {
765 data->topIndex = 0;
767 for (i = 0; i < data->count; i++) {
768 if (data->realY > WBOTTOM(data->bottomList[i])) {
769 data->bottomIndex = i + 1;
771 if (data->realX > WRIGHT(data->rightList[i])) {
772 data->rightIndex = i + 1;
774 if ((data->realX + data->winWidth) < WLEFT(data->leftList[i])) {
775 data->leftIndex = i + 1;
777 if ((data->realY + data->winHeight) < WTOP(data->topList[i])) {
778 data->topIndex = i + 1;
784 static void
785 freeMoveData(MoveData *data)
787 if (data->topList)
788 wfree(data->topList);
789 if (data->leftList)
790 wfree(data->leftList);
791 if (data->rightList)
792 wfree(data->rightList);
793 if (data->bottomList)
794 wfree(data->bottomList);
798 static void
799 updateMoveData(WWindow *wwin, MoveData *data)
801 WScreen *scr = wwin->screen_ptr;
802 WWindow *tmp;
803 int i;
805 data->count = 0;
806 tmp = scr->focused_window;
807 while (tmp) {
808 if (tmp != wwin && scr->current_workspace == tmp->frame->workspace
809 && !tmp->flags.miniaturized
810 && !tmp->flags.hidden
811 && !tmp->flags.obscured
812 && !WFLAGP(tmp, sunken)) {
813 data->topList[data->count] = tmp;
814 data->leftList[data->count] = tmp;
815 data->rightList[data->count] = tmp;
816 data->bottomList[data->count] = tmp;
817 data->count++;
819 tmp = tmp->prev;
822 if (data->count == 0) {
823 data->topIndex = 0;
824 data->leftIndex = 0;
825 data->rightIndex = 0;
826 data->bottomIndex = 0;
827 return;
830 /* order from closest to the border of the screen to farthest */
832 qsort(data->topList, data->count, sizeof(WWindow**), compareWTop);
833 qsort(data->leftList, data->count, sizeof(WWindow**), compareWLeft);
834 qsort(data->rightList, data->count, sizeof(WWindow**), compareWRight);
835 qsort(data->bottomList, data->count, sizeof(WWindow**), compareWBottom);
837 /* figure the position of the window relative to the others */
839 data->topIndex = -1;
840 data->leftIndex = -1;
841 data->rightIndex = -1;
842 data->bottomIndex = -1;
844 if (WTOP(wwin) < WBOTTOM(data->bottomList[0])) {
845 data->bottomIndex = 0;
847 if (WLEFT(wwin) < WRIGHT(data->rightList[0])) {
848 data->rightIndex = 0;
850 if (WRIGHT(wwin) > WLEFT(data->leftList[0])) {
851 data->leftIndex = 0;
853 if (WBOTTOM(wwin) > WTOP(data->topList[0])) {
854 data->topIndex = 0;
856 for (i = 0; i < data->count; i++) {
857 if (WTOP(wwin) >= WBOTTOM(data->bottomList[i])) {
858 data->bottomIndex = i + 1;
860 if (WLEFT(wwin) >= WRIGHT(data->rightList[i])) {
861 data->rightIndex = i + 1;
863 if (WRIGHT(wwin) <= WLEFT(data->leftList[i])) {
864 data->leftIndex = i + 1;
866 if (WBOTTOM(wwin) <= WTOP(data->topList[i])) {
867 data->topIndex = i + 1;
873 static void
874 initMoveData(WWindow *wwin, MoveData *data)
876 int i;
877 WWindow *tmp;
879 memset(data, 0, sizeof(MoveData));
881 for (i = 0, tmp = wwin->screen_ptr->focused_window;
882 tmp != NULL;
883 tmp = tmp->prev, i++);
885 if (i > 1) {
886 data->topList = wmalloc(sizeof(WWindow*) * i);
887 data->leftList = wmalloc(sizeof(WWindow*) * i);
888 data->rightList = wmalloc(sizeof(WWindow*) * i);
889 data->bottomList = wmalloc(sizeof(WWindow*) * i);
891 updateMoveData(wwin, data);
894 data->realX = wwin->frame_x;
895 data->realY = wwin->frame_y;
896 data->calcX = wwin->frame_x;
897 data->calcY = wwin->frame_y;
899 data->winWidth = wwin->frame->core->width +
900 (HAS_BORDER_WITH_SELECT(wwin) ? 2*FRAME_BORDER_WIDTH : 0);
901 data->winHeight = wwin->frame->core->height +
902 (HAS_BORDER_WITH_SELECT(wwin) ? 2*FRAME_BORDER_WIDTH : 0);
906 static Bool
907 checkWorkspaceChange(WWindow *wwin, MoveData *data, Bool opaqueMove)
909 WScreen *scr = wwin->screen_ptr;
910 Bool changed = False;
912 if (data->mouseX <= 1) {
913 if (scr->current_workspace > 0) {
915 crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace - 1,
916 True);
917 changed = True;
918 data->rubCount = 0;
920 } else if (scr->current_workspace == 0 && wPreferences.ws_cycle) {
922 crossWorkspace(scr, wwin, opaqueMove, scr->workspace_count - 1,
923 True);
924 changed = True;
925 data->rubCount = 0;
927 } else if (data->mouseX >= scr->scr_width - 2) {
929 if (scr->current_workspace == scr->workspace_count - 1) {
931 if (wPreferences.ws_cycle
932 || scr->workspace_count == MAX_WORKSPACES) {
934 crossWorkspace(scr, wwin, opaqueMove, 0, False);
935 changed = True;
936 data->rubCount = 0;
938 /* if user insists on trying to go to next workspace even when
939 * it's already the last, create a new one */
940 else if (data->omouseX == data->mouseX
941 && wPreferences.ws_advance) {
943 /* detect user "rubbing" the window against the edge */
944 if (data->rubCount > 0
945 && data->omouseY - data->mouseY > MOVE_THRESHOLD) {
947 data->rubCount = -(data->rubCount + 1);
949 } else if (data->rubCount <= 0
950 && data->mouseY - data->omouseY > MOVE_THRESHOLD) {
952 data->rubCount = -data->rubCount + 1;
955 /* create a new workspace */
956 if (abs(data->rubCount) > 2) {
957 /* go to next workspace */
958 wWorkspaceNew(scr);
960 crossWorkspace(scr, wwin, opaqueMove,
961 scr->current_workspace+1, False);
962 changed = True;
963 data->rubCount = 0;
965 } else if (scr->current_workspace < scr->workspace_count) {
967 /* go to next workspace */
968 crossWorkspace(scr, wwin, opaqueMove,
969 scr->current_workspace+1, False);
970 changed = True;
971 data->rubCount = 0;
973 } else {
974 data->rubCount = 0;
977 return changed;
981 static void
982 updateWindowPosition(WWindow *wwin, MoveData *data, Bool doResistance,
983 Bool opaqueMove, int newMouseX, int newMouseY)
985 WScreen *scr = wwin->screen_ptr;
986 int dx, dy; /* how much mouse moved */
987 int winL, winR, winT, winB; /* requested new window position */
988 int newX, newY; /* actual new window position */
989 Bool hresist, vresist;
990 Bool updateIndex;
991 Bool attract;
993 hresist = False;
994 vresist = False;
996 updateIndex = False;
998 /* check the direction of the movement */
999 dx = newMouseX - data->mouseX;
1000 dy = newMouseY - data->mouseY;
1002 data->omouseX = data->mouseX;
1003 data->omouseY = data->mouseY;
1004 data->mouseX = newMouseX;
1005 data->mouseY = newMouseY;
1007 winL = data->calcX + dx;
1008 winR = data->calcX + data->winWidth + dx;
1009 winT = data->calcY + dy;
1010 winB = data->calcY + data->winHeight + dy;
1012 newX = data->realX;
1013 newY = data->realY;
1015 if (doResistance) {
1016 int l_edge, r_edge;
1017 int edge_l, edge_r;
1018 int t_edge, b_edge;
1019 int edge_t, edge_b;
1020 int resist;
1022 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1023 attract = wPreferences.attract;
1024 /* horizontal movement: check horizontal edge resistances */
1025 if (dx || dy) {
1026 WMRect rect;
1027 int i, head;
1028 /* window is the leftmost window: check against screen edge */
1030 /* Add inter head resistance 1/2 (if needed) */
1031 head = wGetHeadForPointerLocation(scr);
1032 rect = wGetRectForHead(scr, head);
1034 l_edge = WMAX(scr->totalUsableArea[head].x1, rect.pos.x);
1035 edge_l = l_edge - resist;
1036 edge_r = WMIN(scr->totalUsableArea[head].x2, rect.pos.x + rect.size.width);
1037 r_edge = edge_r + resist;
1039 /* 1 */
1040 if ((data->rightIndex >= 0) && (data->rightIndex <= data->count)) {
1041 WWindow *looprw;
1043 for (i = data->rightIndex - 1; i >= 0; i--) {
1044 looprw = data->rightList[i];
1045 if (!(data->realY > WBOTTOM(looprw)
1046 || (data->realY + data->winHeight) < WTOP(looprw))) {
1047 if (attract
1048 || ((data->realX < (WRIGHT(looprw) + 2)) && dx < 0)) {
1049 l_edge = WRIGHT(looprw) + 1;
1050 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1052 break;
1056 if (attract) {
1057 for (i = data->rightIndex; i < data->count; i++) {
1058 looprw = data->rightList[i];
1059 if(!(data->realY > WBOTTOM(looprw)
1060 || (data->realY + data->winHeight) < WTOP(looprw))) {
1061 r_edge = WRIGHT(looprw) + 1;
1062 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1063 break;
1069 if ((data->leftIndex >= 0) && (data->leftIndex <= data->count)) {
1070 WWindow *looprw;
1072 for (i = data->leftIndex - 1; i >= 0; i--) {
1073 looprw = data->leftList[i];
1074 if (!(data->realY > WBOTTOM(looprw)
1075 || (data->realY + data->winHeight) < WTOP(looprw))) {
1076 if (attract
1077 || (((data->realX + data->winWidth) > (WLEFT(looprw) - 1)) && dx > 0)) {
1078 edge_r = WLEFT(looprw);
1079 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1081 break;
1085 if (attract)
1086 for (i = data->leftIndex; i < data->count; i++) {
1087 looprw = data->leftList[i];
1088 if(!(data->realY > WBOTTOM(looprw)
1089 || (data->realY + data->winHeight) < WTOP(looprw))) {
1090 edge_l = WLEFT(looprw);
1091 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1092 break;
1098 printf("%d %d\n",winL,winR);
1099 printf("l_ %d r_ %d _l %d _r %d\n",l_edge,r_edge,edge_l,edge_r);
1102 if ((winL - l_edge) < (r_edge - winL)) {
1103 if (resist > 0) {
1104 if ((attract && winL <= l_edge + resist && winL >= l_edge - resist)
1105 || (dx < 0 && winL <= l_edge && winL >= l_edge - resist)) {
1106 newX = l_edge;
1107 hresist = True;
1110 } else {
1111 if (resist > 0 && attract && winL >= r_edge - resist && winL <= r_edge + resist) {
1112 newX = r_edge;
1113 hresist = True;
1117 if ((winR - edge_l) < (edge_r - winR)) {
1118 if (resist > 0 && attract && winR <= edge_l + resist && winR >= edge_l - resist) {
1119 newX = edge_l - data->winWidth;
1120 hresist = True;
1122 } else {
1123 if (resist > 0) {
1124 if ((attract && winR >= edge_r - resist && winR <= edge_r + resist)
1125 || (dx > 0 && winR >= edge_r && winR <= edge_r + resist)) {
1126 newX = edge_r - data->winWidth;
1127 hresist = True;
1132 /* VeRT */
1133 /* Add inter head resistance 2/2 (if needed) */
1134 t_edge = WMAX(scr->totalUsableArea[head].y1, rect.pos.y);
1135 edge_t = t_edge - resist;
1136 edge_b = WMIN(scr->totalUsableArea[head].y2, rect.pos.y + rect.size.height);
1137 b_edge = edge_b + resist;
1139 if ((data->bottomIndex >= 0) && (data->bottomIndex <= data->count)) {
1140 WWindow *looprw;
1142 for (i = data->bottomIndex - 1; i >= 0; i--) {
1143 looprw = data->bottomList[i];
1144 if (!(data->realX > WRIGHT(looprw)
1145 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1146 if (attract
1147 || ((data->realY < (WBOTTOM(looprw) + 2)) && dy < 0)) {
1148 t_edge = WBOTTOM(looprw) + 1;
1149 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1151 break;
1155 if (attract) {
1156 for (i = data->bottomIndex; i < data->count; i++) {
1157 looprw = data->bottomList[i];
1158 if(!(data->realX > WRIGHT(looprw)
1159 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1160 b_edge = WBOTTOM(looprw) + 1;
1161 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1162 break;
1168 if ((data->topIndex >= 0) && (data->topIndex <= data->count)) {
1169 WWindow *looprw;
1171 for (i = data->topIndex - 1; i >= 0; i--) {
1172 looprw = data->topList[i];
1173 if (!(data->realX > WRIGHT(looprw)
1174 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1175 if (attract
1176 || (((data->realY + data->winHeight) > (WTOP(looprw) - 1)) && dy > 0)) {
1177 edge_b = WTOP(looprw);
1178 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1180 break;
1184 if (attract)
1185 for (i = data->topIndex; i < data->count; i++) {
1186 looprw = data->topList[i];
1187 if(!(data->realX > WRIGHT(looprw)
1188 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1189 edge_t = WTOP(looprw);
1190 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1191 break;
1196 if ((winT - t_edge) < (b_edge - winT)) {
1197 if (resist > 0) {
1198 if ((attract && winT <= t_edge + resist && winT >= t_edge - resist)
1199 || (dy < 0 && winT <= t_edge && winT >= t_edge - resist)) {
1200 newY = t_edge;
1201 vresist = True;
1205 else {
1206 if (resist > 0 && attract && winT >= b_edge - resist && winT <= b_edge + resist) {
1207 newY = b_edge;
1208 vresist = True;
1212 if ((winB - edge_t) < (edge_b - winB)) {
1213 if (resist > 0 && attract && winB <= edge_t + resist && winB >= edge_t - resist) {
1214 newY = edge_t - data->winHeight;
1215 vresist = True;
1218 else {
1219 if (resist > 0) {
1220 if ((attract && winB >= edge_b - resist && winB <= edge_b + resist)
1221 || (dy > 0 && winB >= edge_b && winB <= edge_b + resist)) {
1222 newY = edge_b - data->winHeight;
1223 vresist = True;
1228 /* END VeRT */
1232 /* update window position */
1233 data->calcX += dx;
1234 data->calcY += dy;
1236 if (((dx > 0 && data->calcX - data->realX > 0)
1237 || (dx < 0 && data->calcX - data->realX < 0)) && !hresist)
1238 newX = data->calcX;
1240 if (((dy > 0 && data->calcY - data->realY > 0)
1241 || (dy < 0 && data->calcY - data->realY < 0)) && !vresist)
1242 newY = data->calcY;
1244 if (data->realX != newX || data->realY != newY) {
1246 if (wPreferences.move_display == WDIS_NEW
1247 && !scr->selected_windows) {
1248 showPosition(wwin, data->realX, data->realY);
1250 if (opaqueMove) {
1251 doWindowMove(wwin, scr->selected_windows,
1252 newX - wwin->frame_x,
1253 newY - wwin->frame_y);
1254 } else {
1255 /* erase frames */
1256 drawFrames(wwin, scr->selected_windows,
1257 data->realX - wwin->frame_x,
1258 data->realY - wwin->frame_y);
1261 if (!scr->selected_windows
1262 && wPreferences.move_display == WDIS_FRAME_CENTER) {
1264 moveGeometryDisplayCentered(scr, newX + data->winWidth/2,
1265 newY + data->winHeight/2);
1268 if (!opaqueMove) {
1269 /* draw frames */
1270 drawFrames(wwin, scr->selected_windows,
1271 newX - wwin->frame_x,
1272 newY - wwin->frame_y);
1275 if (!scr->selected_windows) {
1276 showPosition(wwin, newX, newY);
1281 /* recalc relative window position */
1282 if (doResistance && (data->realX != newX || data->realY != newY)) {
1283 updateResistance(wwin, data, newX, newY);
1286 data->realX = newX;
1287 data->realY = newY;
1291 #define _KS KEY_CONTROL_WINDOW_WEIGHT
1293 #define MOVABLE_BIT 0x01
1294 #define RESIZABLE_BIT 0x02
1297 wKeyboardMoveResizeWindow(WWindow *wwin)
1299 WScreen *scr = wwin->screen_ptr;
1300 Window root = scr->root_win;
1301 XEvent event;
1302 int w = wwin->frame->core->width;
1303 int h = wwin->frame->core->height;
1304 int scr_width = wwin->screen_ptr->scr_width;
1305 int scr_height = wwin->screen_ptr->scr_height;
1306 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1307 int src_x = wwin->frame_x;
1308 int src_y = wwin->frame_y;
1309 int done,off_x,off_y,ww,wh;
1310 int kspeed = _KS;
1311 Time lastTime = 0;
1312 KeyCode shiftl, shiftr, ctrll, ctrlmode;
1313 KeySym keysym=NoSymbol;
1314 int moment=0;
1315 int modes = ((IS_MOVABLE(wwin) ? MOVABLE_BIT : 0) |
1316 (IS_RESIZABLE(wwin) ? RESIZABLE_BIT : 0));
1317 int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr)>1)
1318 ? wGetHeadForWindow(wwin)
1319 : scr->xine_info.primary_head);
1321 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1322 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1323 ctrll = XKeysymToKeycode(dpy, XK_Control_L);
1324 ctrlmode=done=off_x=off_y=0;
1326 if (modes == RESIZABLE_BIT) {
1327 ctrlmode = 1;
1330 XSync(dpy, False);
1331 wusleep(10000);
1332 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1334 if (!wwin->flags.selected) {
1335 wUnselectWindows(scr);
1337 XGrabServer(dpy);
1338 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
1339 |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
1340 GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime);
1342 if (wwin->flags.shaded || scr->selected_windows) {
1343 if(scr->selected_windows)
1344 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1345 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1346 if(!scr->selected_windows)
1347 mapPositionDisplay(wwin, src_x, src_y, w, h);
1348 } else {
1349 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1351 ww=w;
1352 wh=h;
1353 while(1) {
1355 looper.ox=off_x;
1356 looper.oy=off_y;
1358 do {
1359 WMMaskEvent(dpy, KeyPressMask | ButtonReleaseMask
1360 | ButtonPressMask | ExposureMask, &event);
1361 if (event.type == Expose) {
1362 WMHandleEvent(&event);
1364 } while (event.type == Expose);
1367 if (wwin->flags.shaded || scr->selected_windows) {
1368 if(scr->selected_windows)
1369 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1370 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1371 /*** I HATE EDGE RESISTANCE - ]d ***/
1373 else {
1374 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
1377 if(ctrlmode)
1378 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
1380 XUngrabServer(dpy);
1381 XSync(dpy, False);
1383 switch (event.type) {
1384 case KeyPress:
1385 /* accelerate */
1386 if (event.xkey.time - lastTime > 50) {
1387 kspeed/=(1 + (event.xkey.time - lastTime)/100);
1388 } else {
1389 if (kspeed < 20) {
1390 kspeed++;
1393 if (kspeed < _KS) kspeed = _KS;
1394 lastTime = event.xkey.time;
1395 if (modes == (MOVABLE_BIT|RESIZABLE_BIT)) {
1396 if ((event.xkey.state & ControlMask) && !wwin->flags.shaded) {
1397 ctrlmode=1;
1398 wUnselectWindows(scr);
1400 else {
1401 ctrlmode=0;
1404 if (event.xkey.keycode == shiftl || event.xkey.keycode == shiftr) {
1405 if (ctrlmode)
1406 cycleGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh, 0);
1407 else
1408 cyclePositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
1410 else {
1412 keysym = XLookupKeysym(&event.xkey, 0);
1413 switch (keysym) {
1414 case XK_Return:
1415 done=2;
1416 break;
1417 case XK_Escape:
1418 done=1;
1419 break;
1420 case XK_Up:
1421 #ifdef XK_KP_Up
1422 case XK_KP_Up:
1423 #endif
1424 case XK_k:
1425 if (ctrlmode){
1426 if (moment != UP)
1427 h = wh;
1428 h-=kspeed;
1429 moment = UP;
1430 if (h < 1) h = 1;
1432 else off_y-=kspeed;
1433 break;
1434 case XK_Down:
1435 #ifdef XK_KP_Down
1436 case XK_KP_Down:
1437 #endif
1438 case XK_j:
1439 if (ctrlmode){
1440 if (moment != DOWN)
1441 h = wh;
1442 h+=kspeed;
1443 moment = DOWN;
1445 else off_y+=kspeed;
1446 break;
1447 case XK_Left:
1448 #ifdef XK_KP_Left
1449 case XK_KP_Left:
1450 #endif
1451 case XK_h:
1452 if (ctrlmode) {
1453 if (moment != LEFT)
1454 w = ww;
1455 w-=kspeed;
1456 if (w < 1) w = 1;
1457 moment = LEFT;
1459 else off_x-=kspeed;
1460 break;
1461 case XK_Right:
1462 #ifdef XK_KP_Right
1463 case XK_KP_Right:
1464 #endif
1465 case XK_l:
1466 if (ctrlmode) {
1467 if (moment != RIGHT)
1468 w = ww;
1469 w+=kspeed;
1470 moment = RIGHT;
1472 else off_x+=kspeed;
1473 break;
1476 ww=w;wh=h;
1477 wh-=vert_border;
1478 wWindowConstrainSize(wwin, &ww, &wh);
1479 wh+=vert_border;
1481 if (wPreferences.ws_cycle){
1482 if (src_x + off_x + ww < 20){
1483 if(!scr->current_workspace) {
1484 wWorkspaceChange(scr, scr->workspace_count-1);
1486 else wWorkspaceChange(scr, scr->current_workspace-1);
1487 off_x += scr_width;
1489 else if (src_x + off_x + 20 > scr_width){
1490 if(scr->current_workspace == scr->workspace_count-1) {
1491 wWorkspaceChange(scr, 0);
1493 else wWorkspaceChange(scr, scr->current_workspace+1);
1494 off_x -= scr_width;
1497 else {
1498 if (src_x + off_x + ww < 20)
1499 off_x = 20 - ww - src_x;
1500 else if (src_x + off_x + 20 > scr_width)
1501 off_x = scr_width - 20 - src_x;
1504 if (src_y + off_y + wh < 20) {
1505 off_y = 20 - wh - src_y;
1507 else if (src_y + off_y + 20 > scr_height) {
1508 off_y = scr_height - 20 - src_y;
1511 break;
1512 case ButtonPress:
1513 case ButtonRelease:
1514 done=1;
1515 break;
1516 case Expose:
1517 WMHandleEvent(&event);
1518 while (XCheckTypedEvent(dpy, Expose, &event)) {
1519 WMHandleEvent(&event);
1521 break;
1523 default:
1524 WMHandleEvent(&event);
1525 break;
1528 XGrabServer(dpy);
1529 /*xxx*/
1531 if (wwin->flags.shaded && !scr->selected_windows){
1532 moveGeometryDisplayCentered(scr, src_x+off_x + w/2, src_y+off_y + h/2);
1533 } else {
1534 if (ctrlmode) {
1535 WMUnmapWidget(scr->gview);
1536 mapGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
1537 } else if(!scr->selected_windows) {
1538 WMUnmapWidget(scr->gview);
1539 mapPositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
1543 if (wwin->flags.shaded || scr->selected_windows) {
1544 if (scr->selected_windows)
1545 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1546 else
1547 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1548 } else {
1549 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
1553 if (ctrlmode) {
1554 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
1555 } else if(!scr->selected_windows)
1556 showPosition(wwin, src_x+off_x, src_y+off_y);
1559 if (done) {
1560 scr->keymove_tick=0;
1562 WMDeleteTimerWithClientData(&looper);
1564 if (wwin->flags.shaded || scr->selected_windows) {
1565 if(scr->selected_windows)
1566 drawFrames(wwin,scr->selected_windows,off_x,off_y);
1567 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
1569 else {
1570 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
1573 if (ctrlmode) {
1574 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
1575 WMUnmapWidget(scr->gview);
1576 } else
1577 WMUnmapWidget(scr->gview);
1579 XUngrabKeyboard(dpy, CurrentTime);
1580 XUngrabPointer(dpy, CurrentTime);
1581 XUngrabServer(dpy);
1583 if(done==2) {
1584 if (wwin->flags.shaded || scr->selected_windows) {
1585 if (!scr->selected_windows) {
1586 wWindowMove(wwin, src_x+off_x, src_y+off_y);
1587 wWindowSynthConfigureNotify(wwin);
1588 } else {
1589 WMArrayIterator iter;
1590 WWindow *foo;
1592 doWindowMove(wwin, scr->selected_windows, off_x, off_y);
1594 WM_ITERATE_ARRAY(scr->selected_windows, foo, iter) {
1595 wWindowSynthConfigureNotify(foo);
1598 } else {
1599 if (wwin->client.width != ww)
1600 wwin->flags.user_changed_width = 1;
1602 if (wwin->client.height != wh - vert_border)
1603 wwin->flags.user_changed_height = 1;
1605 wWindowConfigure(wwin, src_x+off_x, src_y+off_y,
1606 ww, wh - vert_border);
1607 wWindowSynthConfigureNotify(wwin);
1609 wWindowChangeWorkspace(wwin, scr->current_workspace);
1610 wSetFocusTo(scr, wwin);
1613 if (wPreferences.auto_arrange_icons && wXineramaHeads(scr)>1 &&
1614 head != wGetHeadForWindow(wwin)) {
1615 wArrangeIcons(scr, True);
1619 #if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP)
1620 wWorkspaceResizeViewPort(scr, scr->current_workspace);
1621 #endif
1623 return 1;
1630 *----------------------------------------------------------------------
1631 * wMouseMoveWindow--
1632 * Move the named window and the other selected ones (if any),
1633 * interactively. Also shows the position of the window, if only one
1634 * window is being moved.
1635 * If the window is not on the selected window list, the selected
1636 * windows are deselected.
1637 * If shift is pressed during the operation, the position display
1638 * is changed to another type.
1640 * Returns:
1641 * True if the window was moved, False otherwise.
1643 * Side effects:
1644 * The window(s) position is changed, and the client(s) are
1645 * notified about that.
1646 * The position display configuration may be changed.
1647 *----------------------------------------------------------------------
1650 wMouseMoveWindow(WWindow *wwin, XEvent *ev)
1652 WScreen *scr = wwin->screen_ptr;
1653 XEvent event;
1654 Window root = scr->root_win;
1655 KeyCode shiftl, shiftr;
1656 Bool done = False;
1657 int started = 0;
1658 int warped = 0;
1659 /* This needs not to change while moving, else bad things can happen */
1660 int opaqueMove = wPreferences.opaque_move;
1661 MoveData moveData;
1662 int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1)
1663 ? wGetHeadForWindow(wwin)
1664 : scr->xine_info.primary_head);
1665 #ifdef GHOST_WINDOW_MOVE
1666 RImage *rimg = InitGhostWindowMove(scr);
1667 #endif
1669 if (!IS_MOVABLE(wwin))
1670 return False;
1672 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1673 XSetWindowAttributes attr;
1675 attr.save_under = True;
1676 XChangeWindowAttributes(dpy, wwin->frame->core->window,
1677 CWSaveUnder, &attr);
1681 initMoveData(wwin, &moveData);
1683 moveData.mouseX = ev->xmotion.x_root;
1684 moveData.mouseY = ev->xmotion.y_root;
1686 if (!wwin->flags.selected) {
1687 /* this window is not selected, unselect others and move only wwin */
1688 wUnselectWindows(scr);
1690 #ifdef DEBUG
1691 puts("Moving window");
1692 #endif
1693 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1694 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1695 while (!done) {
1696 if (warped) {
1697 int junk;
1698 Window junkw;
1700 /* XWarpPointer() doesn't seem to generate Motion events, so
1701 * we've got to simulate them */
1702 XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
1703 &event.xmotion.y_root, &junk, &junk,
1704 (unsigned *) &junk);
1705 } else {
1706 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
1707 | PointerMotionHintMask
1708 | ButtonReleaseMask | ButtonPressMask | ExposureMask,
1709 &event);
1711 if (event.type == MotionNotify) {
1712 /* compress MotionNotify events */
1713 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
1714 if (!checkMouseSamplingRate(&event))
1715 continue;
1718 switch (event.type) {
1719 case KeyPress:
1720 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1721 && started && !scr->selected_windows) {
1723 if (!opaqueMove) {
1724 drawFrames(wwin, scr->selected_windows,
1725 moveData.realX - wwin->frame_x,
1726 moveData.realY - wwin->frame_y);
1729 if (wPreferences.move_display == WDIS_NEW
1730 && !scr->selected_windows) {
1731 showPosition(wwin, moveData.realX, moveData.realY);
1732 XUngrabServer(dpy);
1734 cyclePositionDisplay(wwin, moveData.realX, moveData.realY,
1735 moveData.winWidth, moveData.winHeight);
1737 if (wPreferences.move_display == WDIS_NEW
1738 && !scr->selected_windows) {
1739 XGrabServer(dpy);
1740 showPosition(wwin, moveData.realX, moveData.realY);
1743 if (!opaqueMove) {
1744 drawFrames(wwin, scr->selected_windows,
1745 moveData.realX - wwin->frame_x,
1746 moveData.realY - wwin->frame_y);
1748 /*} else {
1749 WMHandleEvent(&event); this causes problems needs fixing */
1751 break;
1753 case MotionNotify:
1754 if (started) {
1755 updateWindowPosition(wwin, &moveData,
1756 scr->selected_windows == NULL
1757 && wPreferences.edge_resistance > 0,
1758 opaqueMove,
1759 event.xmotion.x_root,
1760 event.xmotion.y_root);
1762 if (!warped && !wPreferences.no_autowrap) {
1763 int oldWorkspace = scr->current_workspace;
1765 if (wPreferences.move_display == WDIS_NEW
1766 && !scr->selected_windows) {
1767 showPosition(wwin, moveData.realX, moveData.realY);
1768 XUngrabServer(dpy);
1770 if (!opaqueMove) {
1771 drawFrames(wwin, scr->selected_windows,
1772 moveData.realX - wwin->frame_x,
1773 moveData.realY - wwin->frame_y);
1775 if (checkWorkspaceChange(wwin, &moveData, opaqueMove)) {
1776 if (scr->current_workspace != oldWorkspace
1777 && wPreferences.edge_resistance > 0
1778 && scr->selected_windows == NULL)
1779 updateMoveData(wwin, &moveData);
1780 warped = 1;
1782 if (!opaqueMove) {
1783 drawFrames(wwin, scr->selected_windows,
1784 moveData.realX - wwin->frame_x,
1785 moveData.realY - wwin->frame_y);
1787 if (wPreferences.move_display == WDIS_NEW
1788 && !scr->selected_windows) {
1789 XSync(dpy, False);
1790 showPosition(wwin, moveData.realX, moveData.realY);
1791 XGrabServer(dpy);
1793 } else {
1794 warped = 0;
1796 } else if (abs(ev->xmotion.x_root - event.xmotion.x_root) >= MOVE_THRESHOLD
1797 || abs(ev->xmotion.y_root - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1799 XChangeActivePointerGrab(dpy, ButtonMotionMask
1800 | ButtonReleaseMask | ButtonPressMask,
1801 wCursor[WCUR_MOVE], CurrentTime);
1802 started = 1;
1803 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
1804 CurrentTime);
1806 if (!scr->selected_windows)
1807 mapPositionDisplay(wwin, moveData.realX, moveData.realY,
1808 moveData.winWidth, moveData.winHeight);
1810 if (started && !opaqueMove)
1811 drawFrames(wwin, scr->selected_windows, 0, 0);
1813 if (!opaqueMove || (wPreferences.move_display==WDIS_NEW
1814 && !scr->selected_windows)) {
1815 XGrabServer(dpy);
1816 if (wPreferences.move_display==WDIS_NEW)
1817 showPosition(wwin, moveData.realX, moveData.realY);
1820 break;
1822 case ButtonPress:
1823 break;
1825 case ButtonRelease:
1826 if (event.xbutton.button != ev->xbutton.button)
1827 break;
1829 if (started) {
1830 XEvent e;
1831 if (!opaqueMove) {
1832 drawFrames(wwin, scr->selected_windows,
1833 moveData.realX - wwin->frame_x,
1834 moveData.realY - wwin->frame_y);
1835 XSync(dpy, 0);
1836 doWindowMove(wwin, scr->selected_windows,
1837 moveData.realX - wwin->frame_x,
1838 moveData.realY - wwin->frame_y);
1840 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
1841 wWindowSynthConfigureNotify(wwin);
1842 #endif
1843 XUngrabKeyboard(dpy, CurrentTime);
1844 XUngrabServer(dpy);
1845 if (!opaqueMove) {
1846 wWindowChangeWorkspace(wwin, scr->current_workspace);
1847 wSetFocusTo(scr, wwin);
1849 if (wPreferences.move_display == WDIS_NEW)
1850 showPosition(wwin, moveData.realX, moveData.realY);
1852 /* discard all enter/leave events that happened until
1853 * the time the button was released */
1854 while (XCheckTypedEvent(dpy, EnterNotify, &e)) {
1855 if (e.xcrossing.time > event.xbutton.time) {
1856 XPutBackEvent(dpy, &e);
1857 break;
1860 while (XCheckTypedEvent(dpy, LeaveNotify, &e)) {
1861 if (e.xcrossing.time > event.xbutton.time) {
1862 XPutBackEvent(dpy, &e);
1863 break;
1867 if (!scr->selected_windows) {
1868 /* get rid of the geometry window */
1869 WMUnmapWidget(scr->gview);
1872 #ifdef DEBUG
1873 puts("End move window");
1874 #endif
1875 done = True;
1876 break;
1878 default:
1879 if (started && !opaqueMove) {
1880 drawFrames(wwin, scr->selected_windows,
1881 moveData.realX - wwin->frame_x,
1882 moveData.realY - wwin->frame_y);
1883 XUngrabServer(dpy);
1884 WMHandleEvent(&event);
1885 XSync(dpy, False);
1886 XGrabServer(dpy);
1887 drawFrames(wwin, scr->selected_windows,
1888 moveData.realX - wwin->frame_x,
1889 moveData.realY - wwin->frame_y);
1890 } else {
1891 WMHandleEvent(&event);
1893 break;
1897 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1898 XSetWindowAttributes attr;
1900 attr.save_under = False;
1901 XChangeWindowAttributes(dpy, wwin->frame->core->window,
1902 CWSaveUnder, &attr);
1906 freeMoveData(&moveData);
1908 if (started && wPreferences.auto_arrange_icons && wXineramaHeads(scr)>1 &&
1909 head != wGetHeadForWindow(wwin)) {
1910 wArrangeIcons(scr, True);
1913 #if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP)
1914 if (started)
1915 wWorkspaceResizeViewPort(scr, scr->current_workspace);
1916 #endif
1918 return started;
1922 #define RESIZEBAR 1
1923 #define HCONSTRAIN 2
1925 static int
1926 getResizeDirection(WWindow *wwin, int x, int y, int dx, int dy,
1927 int flags)
1929 int w = wwin->frame->core->width - 1;
1930 int cw = wwin->frame->resizebar_corner_width;
1931 int dir;
1933 /* if not resizing through the resizebar */
1934 if (!(flags & RESIZEBAR)) {
1935 int xdir = (abs(x) < (wwin->client.width/2)) ? LEFT : RIGHT;
1936 int ydir = (abs(y) < (wwin->client.height/2)) ? UP : DOWN;
1937 if (abs(dx) < 2 || abs(dy) < 2) {
1938 if (abs(dy) > abs(dx))
1939 xdir = 0;
1940 else
1941 ydir = 0;
1943 return (xdir | ydir);
1946 /* window is too narrow. allow diagonal resize */
1947 if (cw * 2 >= w) {
1948 int ydir;
1950 if (flags & HCONSTRAIN)
1951 ydir = 0;
1952 else
1953 ydir = DOWN;
1954 if (x < cw)
1955 return (LEFT | ydir);
1956 else
1957 return (RIGHT | ydir);
1959 /* vertical resize */
1960 if ((x > cw) && (x < w - cw))
1961 return DOWN;
1963 if (x < cw)
1964 dir = LEFT;
1965 else
1966 dir = RIGHT;
1968 if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
1969 dir |= DOWN;
1971 return dir;
1975 void
1976 wMouseResizeWindow(WWindow *wwin, XEvent *ev)
1978 XEvent event;
1979 WScreen *scr = wwin->screen_ptr;
1980 Window root = scr->root_win;
1981 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1982 int fw = wwin->frame->core->width;
1983 int fh = wwin->frame->core->height;
1984 int fx = wwin->frame_x;
1985 int fy = wwin->frame_y;
1986 int is_resizebar = (wwin->frame->resizebar
1987 && ev->xany.window==wwin->frame->resizebar->window);
1988 int orig_x, orig_y;
1989 int started;
1990 int dw, dh;
1991 int rw = fw, rh = fh;
1992 int rx1, ry1, rx2, ry2;
1993 int res = 0;
1994 KeyCode shiftl, shiftr;
1995 int h = 0;
1996 int orig_fx = fx;
1997 int orig_fy = fy;
1998 int orig_fw = fw;
1999 int orig_fh = fh;
2000 int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr)>1)
2001 ? wGetHeadForWindow(wwin)
2002 : scr->xine_info.primary_head);
2004 if (!IS_RESIZABLE(wwin))
2005 return;
2007 if (wwin->flags.shaded) {
2008 wwarning("internal error: tryein");
2009 return;
2011 orig_x = ev->xbutton.x_root;
2012 orig_y = ev->xbutton.y_root;
2014 started = 0;
2015 #ifdef DEBUG
2016 puts("Resizing window");
2017 #endif
2019 wUnselectWindows(scr);
2020 rx1 = fx;
2021 rx2 = fx + fw - 1;
2022 ry1 = fy;
2023 ry2 = fy + fh - 1;
2024 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
2025 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
2026 if (HAS_TITLEBAR(wwin))
2027 h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
2028 else
2029 h = 0;
2030 while (1) {
2031 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
2032 | ButtonReleaseMask | PointerMotionHintMask
2033 | ButtonPressMask | ExposureMask, &event);
2034 if (!checkMouseSamplingRate(&event))
2035 continue;
2037 switch (event.type) {
2038 case KeyPress:
2039 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2040 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
2041 && started) {
2042 drawTransparentFrame(wwin, fx, fy, fw, fh);
2043 cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
2044 drawTransparentFrame(wwin, fx, fy, fw, fh);
2046 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2047 break;
2049 case MotionNotify:
2050 if (started) {
2051 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
2053 dw = 0;
2054 dh = 0;
2056 orig_fx = fx;
2057 orig_fy = fy;
2058 orig_fw = fw;
2059 orig_fh = fh;
2061 if (res & LEFT)
2062 dw = orig_x - event.xmotion.x_root;
2063 else if (res & RIGHT)
2064 dw = event.xmotion.x_root - orig_x;
2065 if (res & UP)
2066 dh = orig_y - event.xmotion.y_root;
2067 else if (res & DOWN)
2068 dh = event.xmotion.y_root - orig_y;
2070 orig_x = event.xmotion.x_root;
2071 orig_y = event.xmotion.y_root;
2073 rw += dw;
2074 rh += dh;
2075 fw = rw;
2076 fh = rh - vert_border;
2077 wWindowConstrainSize(wwin, &fw, &fh);
2078 fh += vert_border;
2079 if (res & LEFT)
2080 fx = rx2 - fw + 1;
2081 else if (res & RIGHT)
2082 fx = rx1;
2083 if (res & UP)
2084 fy = ry2 - fh + 1;
2085 else if (res & DOWN)
2086 fy = ry1;
2087 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
2088 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
2089 int tx, ty;
2090 Window junkw;
2091 int flags;
2093 XTranslateCoordinates(dpy, root, wwin->frame->core->window,
2094 orig_x, orig_y, &tx, &ty, &junkw);
2096 /* check if resizing through resizebar */
2097 if (is_resizebar)
2098 flags = RESIZEBAR;
2099 else
2100 flags = 0;
2102 if (is_resizebar && ((ev->xbutton.state & ShiftMask)
2103 || abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
2104 flags |= HCONSTRAIN;
2106 res = getResizeDirection(wwin, tx, ty,
2107 orig_x - event.xmotion.x_root,
2108 orig_y - event.xmotion.y_root, flags);
2110 if (res == (UP|LEFT))
2111 XChangeActivePointerGrab(dpy, ButtonMotionMask
2112 | ButtonReleaseMask | ButtonPressMask,
2113 wCursor[WCUR_TOPLEFTRESIZE], CurrentTime);
2114 else if (res == (UP|RIGHT))
2115 XChangeActivePointerGrab(dpy, ButtonMotionMask
2116 | ButtonReleaseMask | ButtonPressMask,
2117 wCursor[WCUR_TOPRIGHTRESIZE], CurrentTime);
2118 else if (res == (DOWN|LEFT))
2119 XChangeActivePointerGrab(dpy, ButtonMotionMask
2120 | ButtonReleaseMask | ButtonPressMask,
2121 wCursor[WCUR_BOTTOMLEFTRESIZE], CurrentTime);
2122 else if (res == (DOWN|RIGHT))
2123 XChangeActivePointerGrab(dpy, ButtonMotionMask
2124 | ButtonReleaseMask | ButtonPressMask,
2125 wCursor[WCUR_BOTTOMRIGHTRESIZE], CurrentTime);
2126 else if (res == DOWN || res == UP)
2127 XChangeActivePointerGrab(dpy, ButtonMotionMask
2128 | ButtonReleaseMask | ButtonPressMask,
2129 wCursor[WCUR_VERTICALRESIZE], CurrentTime);
2130 else if (res & (DOWN|UP))
2131 XChangeActivePointerGrab(dpy, ButtonMotionMask
2132 | ButtonReleaseMask | ButtonPressMask,
2133 wCursor[WCUR_VERTICALRESIZE], CurrentTime);
2134 else if (res & (LEFT|RIGHT))
2135 XChangeActivePointerGrab(dpy, ButtonMotionMask
2136 | ButtonReleaseMask | ButtonPressMask,
2137 wCursor[WCUR_HORIZONRESIZE], CurrentTime);
2139 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
2140 CurrentTime);
2142 XGrabServer(dpy);
2144 /* Draw the resize frame for the first time. */
2145 mapGeometryDisplay(wwin, fx, fy, fw, fh);
2147 drawTransparentFrame(wwin, fx, fy, fw, fh);
2149 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2151 started = 1;
2153 if (started) {
2154 if (wPreferences.size_display == WDIS_FRAME_CENTER) {
2155 drawTransparentFrame(wwin, orig_fx, orig_fy,
2156 orig_fw, orig_fh);
2157 moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
2158 drawTransparentFrame(wwin, fx, fy, fw, fh);
2159 } else {
2160 drawTransparentFrame(wwin, orig_fx, orig_fy,
2161 orig_fw, orig_fh);
2162 drawTransparentFrame(wwin, fx, fy, fw, fh);
2164 if (fh != orig_fh || fw != orig_fw) {
2165 if (wPreferences.size_display == WDIS_NEW) {
2166 showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw,
2167 orig_fy + orig_fh, res);
2169 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2172 break;
2174 case ButtonPress:
2175 break;
2177 case ButtonRelease:
2178 if (event.xbutton.button != ev->xbutton.button)
2179 break;
2181 if (started) {
2182 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2184 drawTransparentFrame(wwin, fx, fy, fw, fh);
2186 XUngrabKeyboard(dpy, CurrentTime);
2187 WMUnmapWidget(scr->gview);
2188 XUngrabServer(dpy);
2190 if (wwin->client.width != fw)
2191 wwin->flags.user_changed_width = 1;
2193 if (wwin->client.height != fh - vert_border)
2194 wwin->flags.user_changed_height = 1;
2196 wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
2198 #ifdef DEBUG
2199 puts("End resize window");
2200 #endif
2201 return;
2203 default:
2204 WMHandleEvent(&event);
2208 if (wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 &&
2209 head != wGetHeadForWindow(wwin)) {
2210 wArrangeIcons(scr, True);
2213 #if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP)
2214 wWorkspaceResizeViewPort(scr, scr->current_workspace);
2215 #endif
2218 #undef LEFT
2219 #undef RIGHT
2220 #undef HORIZONTAL
2221 #undef UP
2222 #undef DOWN
2223 #undef VERTICAL
2224 #undef HCONSTRAIN
2225 #undef RESIZEBAR
2227 void
2228 wUnselectWindows(WScreen *scr)
2230 WWindow *wwin;
2232 if (!scr->selected_windows)
2233 return;
2235 while (WMGetArrayItemCount(scr->selected_windows)) {
2236 wwin = WMGetFromArray(scr->selected_windows, 0);
2237 if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
2238 wIconSelect(wwin->icon);
2240 wSelectWindow(wwin, False);
2242 WMFreeArray(scr->selected_windows);
2243 scr->selected_windows = NULL;
2246 #ifndef LITE
2247 static void
2248 selectWindowsInside(WScreen *scr, int x1, int y1, int x2, int y2)
2250 WWindow *tmpw;
2252 /* select the windows and put them in the selected window list */
2253 tmpw = scr->focused_window;
2254 while (tmpw != NULL) {
2255 if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
2256 if ((tmpw->frame->workspace == scr->current_workspace
2257 || IS_OMNIPRESENT(tmpw))
2258 && (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1)
2259 && (tmpw->frame->core->width + tmpw->frame_x <= x2)
2260 && (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
2261 wSelectWindow(tmpw, True);
2264 tmpw = tmpw->prev;
2269 void
2270 wSelectWindows(WScreen *scr, XEvent *ev)
2272 XEvent event;
2273 Window root = scr->root_win;
2274 GC gc = scr->frame_gc;
2275 int xp = ev->xbutton.x_root;
2276 int yp = ev->xbutton.y_root;
2277 int w = 0, h = 0;
2278 int x = xp, y = yp;
2280 #ifdef DEBUG
2281 puts("Selecting windows");
2282 #endif
2283 if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
2284 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
2285 GrabModeAsync, None, wCursor[WCUR_DEFAULT],
2286 CurrentTime) != Success) {
2287 return;
2289 XGrabServer(dpy);
2291 wUnselectWindows(scr);
2293 XDrawRectangle(dpy, root, gc, xp, yp, w, h);
2294 while (1) {
2295 WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask
2296 | ButtonPressMask, &event);
2298 switch (event.type) {
2299 case MotionNotify:
2300 XDrawRectangle(dpy, root, gc, x, y, w, h);
2301 x = event.xmotion.x_root;
2302 if (x < xp) {
2303 w = xp - x;
2304 } else {
2305 w = x - xp;
2306 x = xp;
2308 y = event.xmotion.y_root;
2309 if (y < yp) {
2310 h = yp - y;
2311 } else {
2312 h = y - yp;
2313 y = yp;
2315 XDrawRectangle(dpy, root, gc, x, y, w, h);
2316 break;
2318 case ButtonPress:
2319 break;
2321 case ButtonRelease:
2322 if (event.xbutton.button != ev->xbutton.button)
2323 break;
2325 XDrawRectangle(dpy, root, gc, x, y, w, h);
2326 XUngrabServer(dpy);
2327 XUngrabPointer(dpy, CurrentTime);
2328 selectWindowsInside(scr, x, y, x + w, y + h);
2330 #ifdef KWM_HINTS
2331 wKWMSelectRootRegion(scr, xp, yp, w, h,
2332 event.xbutton.state & ControlMask);
2333 #endif /* KWM_HINTS */
2335 #ifdef DEBUG
2336 puts("End window selection");
2337 #endif
2338 return;
2340 default:
2341 WMHandleEvent(&event);
2342 break;
2346 #endif /* !LITE */
2348 void
2349 InteractivePlaceWindow(WWindow *wwin, int *x_ret, int *y_ret,
2350 unsigned width, unsigned height)
2352 WScreen *scr = wwin->screen_ptr;
2353 Window root = scr->root_win;
2354 int x, y, h = 0;
2355 XEvent event;
2356 KeyCode shiftl, shiftr;
2357 Window junkw;
2358 int junk;
2360 if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
2361 GrabModeAsync, GrabModeAsync, None,
2362 wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
2363 *x_ret = 0;
2364 *y_ret = 0;
2365 return;
2367 if (HAS_TITLEBAR(wwin)) {
2368 h = WMFontHeight(scr->title_font) + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
2369 height += h;
2371 if (HAS_RESIZEBAR(wwin)) {
2372 height += RESIZEBAR_HEIGHT;
2374 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
2375 XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk,
2376 (unsigned *) &junk);
2377 mapPositionDisplay(wwin, x - width/2, y - h/2, width, height);
2379 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2381 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
2382 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
2383 while (1) {
2384 WMMaskEvent(dpy, PointerMotionMask|ButtonPressMask|ExposureMask|KeyPressMask,
2385 &event);
2387 if (!checkMouseSamplingRate(&event))
2388 continue;
2390 switch (event.type) {
2391 case KeyPress:
2392 if ((event.xkey.keycode == shiftl)
2393 || (event.xkey.keycode == shiftr)) {
2394 drawTransparentFrame(wwin,
2395 x - width/2, y - h/2, width, height);
2396 cyclePositionDisplay(wwin,
2397 x - width/2, y - h/2, width, height);
2398 drawTransparentFrame(wwin,
2399 x - width/2, y - h/2, width, height);
2401 break;
2403 case MotionNotify:
2404 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2406 x = event.xmotion.x_root;
2407 y = event.xmotion.y_root;
2409 if (wPreferences.move_display == WDIS_FRAME_CENTER)
2410 moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
2412 showPosition(wwin, x - width/2, y - h/2);
2414 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2416 break;
2418 case ButtonPress:
2419 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
2420 XSync(dpy, 0);
2421 *x_ret = x - width/2;
2422 *y_ret = y - h/2;
2423 XUngrabPointer(dpy, CurrentTime);
2424 XUngrabKeyboard(dpy, CurrentTime);
2425 /* get rid of the geometry window */
2426 WMUnmapWidget(scr->gview);
2427 return;
2429 default:
2430 WMHandleEvent(&event);
2431 break;