activate XGrabServer again
[wmaker-crm.git] / src / moveres.c
blobf798064ceebd49d3453ff40976edac1a3bf75140
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>
49 /* How many different types of geometry/position
50 display thingies are there? */
51 #define NUM_DISPLAYS 5
53 #define LEFT 1
54 #define RIGHT 2
55 #define HORIZONTAL (LEFT|RIGHT)
56 #define UP 4
57 #define DOWN 8
58 #define VERTICAL (UP|DOWN)
60 /* True if window currently has a border. This also includes borderless
61 * windows which are currently selected
63 #define HAS_BORDER_WITH_SELECT(w) ((w)->flags.selected || HAS_BORDER(w))
65 /****** Global Variables ******/
66 extern Time LastTimestamp;
68 extern Cursor wCursor[WCUR_LAST];
70 extern WPreferences wPreferences;
72 extern Atom _XA_WM_PROTOCOLS;
75 *----------------------------------------------------------------------
76 * checkMouseSamplingRate-
77 * For lowering the mouse motion sampling rate for machines where
78 * it's too high (SGIs). If it returns False then the event should be
79 * ignored.
80 *----------------------------------------------------------------------
82 static Bool checkMouseSamplingRate(XEvent * ev)
84 static Time previousMotion = 0;
86 if (ev->type == MotionNotify) {
87 if (ev->xmotion.time - previousMotion < DELAY_BETWEEN_MOUSE_SAMPLING) {
88 return False;
89 } else {
90 previousMotion = ev->xmotion.time;
93 return True;
97 *----------------------------------------------------------------------
98 * moveGeometryDisplayCentered
100 * routine that moves the geometry/position window on scr so it is
101 * centered over the given coordinates (x,y). Also the window position
102 * is clamped so it stays on the screen at all times.
103 *----------------------------------------------------------------------
105 static void moveGeometryDisplayCentered(WScreen * scr, int x, int y)
107 unsigned int w = WMWidgetWidth(scr->gview);
108 unsigned int h = WMWidgetHeight(scr->gview);
109 int x1 = 0, y1 = 0, x2 = scr->scr_width, y2 = scr->scr_height;
111 x -= w / 2;
112 y -= h / 2;
114 /* dead area check */
115 if (scr->xine_info.count) {
116 WMRect rect;
117 int head, flags;
119 rect.pos.x = x;
120 rect.pos.y = y;
121 rect.size.width = w;
122 rect.size.height = h;
124 head = wGetRectPlacementInfo(scr, rect, &flags);
126 if (flags & (XFLAG_DEAD | XFLAG_PARTIAL)) {
127 rect = wGetRectForHead(scr, head);
128 x1 = rect.pos.x;
129 y1 = rect.pos.y;
130 x2 = x1 + rect.size.width;
131 y2 = y1 + rect.size.height;
135 if (x < x1 + 1)
136 x = x1 + 1;
137 else if (x > (x2 - w))
138 x = x2 - w;
140 if (y < y1 + 1)
141 y = y1 + 1;
142 else if (y > (y2 - h))
143 y = y2 - h;
145 WMMoveWidget(scr->gview, x, y);
148 static void showPosition(WWindow * wwin, int x, int y)
150 WScreen *scr = wwin->screen_ptr;
152 if (wPreferences.move_display == WDIS_NEW) {
153 #if 0
154 int width = wwin->frame->core->width;
155 int height = wwin->frame->core->height;
157 GC lgc = scr->line_gc;
158 XSetForeground(dpy, lgc, scr->line_pixel);
159 sprintf(num, "%i", x);
161 XDrawLine(dpy, scr->root_win, lgc, 0, y - 1, scr->scr_width, y - 1);
162 XDrawLine(dpy, scr->root_win, lgc, 0, y + height + 2, scr->scr_width, y + height + 2);
163 XDrawLine(dpy, scr->root_win, lgc, x - 1, 0, x - 1, scr->scr_height);
164 XDrawLine(dpy, scr->root_win, lgc, x + width + 2, 0, x + width + 2, scr->scr_height);
165 #endif
166 } else {
167 #ifdef VIRTUAL_DESKTOP
168 WSetGeometryViewShownPosition(scr->gview,
169 x + scr->workspaces[scr->current_workspace]->view_x,
170 y + scr->workspaces[scr->current_workspace]->view_y);
171 #else
172 WSetGeometryViewShownPosition(scr->gview, x, y);
173 #endif
177 static void cyclePositionDisplay(WWindow * wwin, int x, int y, int w, int h)
179 WScreen *scr = wwin->screen_ptr;
180 WMRect rect;
182 wPreferences.move_display++;
183 wPreferences.move_display %= NUM_DISPLAYS;
185 if (wPreferences.move_display == WDIS_NEW) {
186 wPreferences.move_display++;
187 wPreferences.move_display %= NUM_DISPLAYS;
190 if (wPreferences.move_display == WDIS_NONE) {
191 WMUnmapWidget(scr->gview);
192 } else {
193 if (wPreferences.move_display == WDIS_CENTER) {
194 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
195 moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width / 2,
196 rect.pos.y + rect.size.height / 2);
197 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
198 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
199 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
200 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
201 moveGeometryDisplayCentered(scr, x + w / 2, y + h / 2);
203 WMMapWidget(scr->gview);
207 static void mapPositionDisplay(WWindow * wwin, int x, int y, int w, int h)
209 WScreen *scr = wwin->screen_ptr;
210 WMRect rect;
212 if (wPreferences.move_display == WDIS_NEW || wPreferences.move_display == WDIS_NONE) {
213 return;
214 } else if (wPreferences.move_display == WDIS_CENTER) {
215 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
216 moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width / 2,
217 rect.pos.y + rect.size.height / 2);
218 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
219 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
220 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
221 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
222 moveGeometryDisplayCentered(scr, x + w / 2, y + h / 2);
224 WMMapWidget(scr->gview);
225 WSetGeometryViewShownPosition(scr->gview, x, y);
228 static void showGeometry(WWindow * wwin, int x1, int y1, int x2, int y2, int direction)
230 WScreen *scr = wwin->screen_ptr;
231 Window root = scr->root_win;
232 GC gc = scr->line_gc;
233 int ty, by, my, x, y, mx, s;
234 char num[16];
235 XSegment segment[4];
236 int fw, fh;
238 /* This seems necessary for some odd reason (too lazy to write x1-1 and
239 * x2-1 everywhere below in the code). But why only for x? */
240 x1--;
241 x2--;
243 if (HAS_BORDER_WITH_SELECT(wwin)) {
244 x1 += FRAME_BORDER_WIDTH;
245 x2 += FRAME_BORDER_WIDTH;
246 y1 += FRAME_BORDER_WIDTH;
247 y2 += FRAME_BORDER_WIDTH;
250 ty = y1 + wwin->frame->top_width;
251 by = y2 - wwin->frame->bottom_width;
253 if (wPreferences.size_display == WDIS_NEW) {
254 fw = XTextWidth(scr->tech_draw_font, "8888", 4);
255 fh = scr->tech_draw_font->ascent + scr->tech_draw_font->descent;
257 XSetForeground(dpy, gc, scr->line_pixel);
259 /* vertical geometry */
260 if (((direction & LEFT) && (x2 < scr->scr_width - fw)) || (x1 < fw)) {
261 x = x2;
262 s = -15;
263 } else {
264 x = x1;
265 s = 15;
267 my = (ty + by) / 2;
269 /* top arrow & end bar */
270 segment[0].x1 = x - (s + 6);
271 segment[0].y1 = ty;
272 segment[0].x2 = x - (s - 10);
273 segment[0].y2 = ty;
275 /* arrowhead */
276 segment[1].x1 = x - (s - 2);
277 segment[1].y1 = ty + 1;
278 segment[1].x2 = x - (s - 5);
279 segment[1].y2 = ty + 7;
281 segment[2].x1 = x - (s - 2);
282 segment[2].y1 = ty + 1;
283 segment[2].x2 = x - (s + 1);
284 segment[2].y2 = ty + 7;
286 /* line */
287 segment[3].x1 = x - (s - 2);
288 segment[3].y1 = ty + 1;
289 segment[3].x2 = x - (s - 2);
290 segment[3].y2 = my - fh / 2 - 1;
292 XDrawSegments(dpy, root, gc, segment, 4);
294 /* bottom arrow & end bar */
295 segment[0].y1 = by;
296 segment[0].y2 = by;
298 /* arrowhead */
299 segment[1].y1 = by - 1;
300 segment[1].y2 = by - 7;
302 segment[2].y1 = by - 1;
303 segment[2].y2 = by - 7;
305 /* line */
306 segment[3].y1 = my + fh / 2 + 2;
307 segment[3].y2 = by - 1;
309 XDrawSegments(dpy, root, gc, segment, 4);
311 snprintf(num, sizeof(num), "%i", (by - ty - wwin->normal_hints->base_height) /
312 wwin->normal_hints->height_inc);
313 fw = XTextWidth(scr->tech_draw_font, num, strlen(num));
315 /* Display the height. */
316 XSetFont(dpy, gc, scr->tech_draw_font->fid);
317 XDrawString(dpy, root, gc, x - s + 3 - fw / 2, my + scr->tech_draw_font->ascent - fh / 2 + 1, num,
318 strlen(num));
320 /* horizontal geometry */
321 if (y1 < 15) {
322 y = y2;
323 s = -15;
324 } else {
325 y = y1;
326 s = 15;
328 mx = x1 + (x2 - x1) / 2;
329 snprintf(num, sizeof(num), "%i", (x2 - x1 - wwin->normal_hints->base_width) /
330 wwin->normal_hints->width_inc);
331 fw = XTextWidth(scr->tech_draw_font, num, strlen(num));
333 /* left arrow & end bar */
334 segment[0].x1 = x1;
335 segment[0].y1 = y - (s + 6);
336 segment[0].x2 = x1;
337 segment[0].y2 = y - (s - 10);
339 /* arrowhead */
340 segment[1].x1 = x1 + 7;
341 segment[1].y1 = y - (s + 1);
342 segment[1].x2 = x1 + 1;
343 segment[1].y2 = y - (s - 2);
345 segment[2].x1 = x1 + 1;
346 segment[2].y1 = y - (s - 2);
347 segment[2].x2 = x1 + 7;
348 segment[2].y2 = y - (s - 5);
350 /* line */
351 segment[3].x1 = x1 + 1;
352 segment[3].y1 = y - (s - 2);
353 segment[3].x2 = mx - fw / 2 - 2;
354 segment[3].y2 = y - (s - 2);
356 XDrawSegments(dpy, root, gc, segment, 4);
358 /* right arrow & end bar */
359 segment[0].x1 = x2 + 1;
360 segment[0].x2 = x2 + 1;
362 /* arrowhead */
363 segment[1].x1 = x2 - 6;
364 segment[1].x2 = x2;
366 segment[2].x1 = x2;
367 segment[2].x2 = x2 - 6;
369 /* line */
370 segment[3].x1 = mx + fw / 2 + 2;
371 segment[3].x2 = x2;
373 XDrawSegments(dpy, root, gc, segment, 4);
375 /* Display the width. */
376 XDrawString(dpy, root, gc, mx - fw / 2 + 1, y - s + scr->tech_draw_font->ascent - fh / 2 + 1, num,
377 strlen(num));
378 } else {
379 WSetGeometryViewShownSize(scr->gview, (x2 - x1 - wwin->normal_hints->base_width)
380 / wwin->normal_hints->width_inc,
381 (by - ty - wwin->normal_hints->base_height)
382 / wwin->normal_hints->height_inc);
386 static void cycleGeometryDisplay(WWindow * wwin, int x, int y, int w, int h, int dir)
388 WScreen *scr = wwin->screen_ptr;
389 WMRect rect;
391 wPreferences.size_display++;
392 wPreferences.size_display %= NUM_DISPLAYS;
394 if (wPreferences.size_display == WDIS_NEW || wPreferences.size_display == WDIS_NONE) {
395 WMUnmapWidget(scr->gview);
396 } else {
397 if (wPreferences.size_display == WDIS_CENTER) {
398 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
399 moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width / 2,
400 rect.pos.y + rect.size.height / 2);
401 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
402 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
403 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
404 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
405 moveGeometryDisplayCentered(scr, x + w / 2, y + h / 2);
407 WMMapWidget(scr->gview);
408 showGeometry(wwin, x, y, x + w, y + h, dir);
412 static void mapGeometryDisplay(WWindow * wwin, int x, int y, int w, int h)
414 WScreen *scr = wwin->screen_ptr;
415 WMRect rect;
417 if (wPreferences.size_display == WDIS_NEW || wPreferences.size_display == WDIS_NONE)
418 return;
420 if (wPreferences.size_display == WDIS_CENTER) {
421 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
422 moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width / 2,
423 rect.pos.y + rect.size.height / 2);
424 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
425 rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
426 moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
427 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
428 moveGeometryDisplayCentered(scr, x + w / 2, y + h / 2);
430 WMMapWidget(scr->gview);
431 showGeometry(wwin, x, y, x + w, y + h, 0);
434 static void doWindowMove(WWindow * wwin, WMArray * array, int dx, int dy)
436 WWindow *tmpw;
437 WScreen *scr = wwin->screen_ptr;
438 int x, y;
440 if (!array || !WMGetArrayItemCount(array)) {
441 wWindowMove(wwin, wwin->frame_x + dx, wwin->frame_y + dy);
442 } else {
443 WMArrayIterator iter;
445 WM_ITERATE_ARRAY(array, tmpw, iter) {
446 x = tmpw->frame_x + dx;
447 y = tmpw->frame_y + dy;
449 #if 1 /* XXX: with xinerama patch was #if 0, check this */
450 /* don't let windows become unreachable */
452 if (x + (int)tmpw->frame->core->width < 20)
453 x = 20 - (int)tmpw->frame->core->width;
454 else if (x + 20 > scr->scr_width)
455 x = scr->scr_width - 20;
457 if (y + (int)tmpw->frame->core->height < 20)
458 y = 20 - (int)tmpw->frame->core->height;
459 else if (y + 20 > scr->scr_height)
460 y = scr->scr_height - 20;
461 #else
462 wScreenBringInside(scr, &x, &y,
463 (int)tmpw->frame->core->width, (int)tmpw->frame->core->height);
464 #endif
466 wWindowMove(tmpw, x, y);
471 static void drawTransparentFrame(WWindow * wwin, int x, int y, int width, int height)
473 Window root = wwin->screen_ptr->root_win;
474 GC gc = wwin->screen_ptr->frame_gc;
475 int h = 0;
476 int bottom = 0;
478 if (HAS_BORDER_WITH_SELECT(wwin)) {
479 x += FRAME_BORDER_WIDTH;
480 y += FRAME_BORDER_WIDTH;
483 if (HAS_TITLEBAR(wwin) && !wwin->flags.shaded) {
484 h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance +
485 TITLEBAR_EXTEND_SPACE) * 2;
487 if (HAS_RESIZEBAR(wwin) && !wwin->flags.shaded) {
488 /* Can't use wwin-frame->bottom_width because, in some cases
489 (e.g. interactive placement), frame does not point to anything. */
490 bottom = RESIZEBAR_HEIGHT;
492 XDrawRectangle(dpy, root, gc, x - 1, y - 1, width + 1, height + 1);
494 if (h > 0) {
495 XDrawLine(dpy, root, gc, x, y + h - 1, x + width, y + h - 1);
497 if (bottom > 0) {
498 XDrawLine(dpy, root, gc, x, y + height - bottom, x + width, y + height - bottom);
502 static void drawFrames(WWindow * wwin, WMArray * array, int dx, int dy)
504 WWindow *tmpw;
505 int scr_width = wwin->screen_ptr->scr_width;
506 int scr_height = wwin->screen_ptr->scr_height;
507 int x, y;
509 if (!array) {
511 x = wwin->frame_x + dx;
512 y = wwin->frame_y + dy;
514 drawTransparentFrame(wwin, x, y, wwin->frame->core->width, wwin->frame->core->height);
516 } else {
517 WMArrayIterator iter;
519 WM_ITERATE_ARRAY(array, tmpw, iter) {
520 x = tmpw->frame_x + dx;
521 y = tmpw->frame_y + dy;
523 /* don't let windows become unreachable */
524 #if 1 /* XXX: was 0 in XINERAMA patch, check */
525 if (x + (int)tmpw->frame->core->width < 20)
526 x = 20 - (int)tmpw->frame->core->width;
527 else if (x + 20 > scr_width)
528 x = scr_width - 20;
530 if (y + (int)tmpw->frame->core->height < 20)
531 y = 20 - (int)tmpw->frame->core->height;
532 else if (y + 20 > scr_height)
533 y = scr_height - 20;
535 #else
536 wScreenBringInside(wwin->screen_ptr, &x, &y,
537 (int)tmpw->frame->core->width, (int)tmpw->frame->core->height);
538 #endif
540 drawTransparentFrame(tmpw, x, y, tmpw->frame->core->width, tmpw->frame->core->height);
545 static void flushMotion()
547 XEvent ev;
549 XSync(dpy, False);
550 while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
553 static void crossWorkspace(WScreen * scr, WWindow * wwin, int opaque_move, int new_workspace, int rewind)
555 /* do not let window be unmapped */
556 if (opaque_move) {
557 wwin->flags.changing_workspace = 1;
558 wWindowChangeWorkspace(wwin, new_workspace);
560 /* go to new workspace */
561 wWorkspaceChange(scr, new_workspace);
563 wwin->flags.changing_workspace = 0;
565 if (rewind)
566 XWarpPointer(dpy, None, None, 0, 0, 0, 0, scr->scr_width - 20, 0);
567 else
568 XWarpPointer(dpy, None, None, 0, 0, 0, 0, -(scr->scr_width - 20), 0);
570 flushMotion();
572 if (!opaque_move) {
573 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
574 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
575 GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
579 typedef struct {
580 /* arrays of WWindows sorted by the respective border position */
581 WWindow **topList; /* top border */
582 WWindow **leftList; /* left border */
583 WWindow **rightList; /* right border */
584 WWindow **bottomList; /* bottom border */
585 int count;
587 /* index of window in the above lists indicating the relative position
588 * of the window with the others */
589 int topIndex;
590 int leftIndex;
591 int rightIndex;
592 int bottomIndex;
594 int rubCount; /* for workspace switching */
596 int winWidth, winHeight; /* width/height of the window */
597 int realX, realY; /* actual position of the window */
598 int calcX, calcY; /* calculated position of window */
599 int omouseX, omouseY; /* old mouse position */
600 int mouseX, mouseY; /* last known position of the pointer */
601 } MoveData;
603 #define WTOP(w) (w)->frame_y
604 #define WLEFT(w) (w)->frame_x
605 #define WRIGHT(w) ((w)->frame_x + (int)(w)->frame->core->width - 1 + \
606 (HAS_BORDER_WITH_SELECT(w) ? 2*FRAME_BORDER_WIDTH : 0))
607 #define WBOTTOM(w) ((w)->frame_y + (int)(w)->frame->core->height - 1 + \
608 (HAS_BORDER_WITH_SELECT(w) ? 2*FRAME_BORDER_WIDTH : 0))
610 static int compareWTop(const void *a, const void *b)
612 WWindow *wwin1 = *(WWindow **) a;
613 WWindow *wwin2 = *(WWindow **) b;
615 if (WTOP(wwin1) > WTOP(wwin2))
616 return -1;
617 else if (WTOP(wwin1) < WTOP(wwin2))
618 return 1;
619 else
620 return 0;
623 static int 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;
636 static int compareWRight(const void *a, const void *b)
638 WWindow *wwin1 = *(WWindow **) a;
639 WWindow *wwin2 = *(WWindow **) b;
641 if (WRIGHT(wwin1) < WRIGHT(wwin2))
642 return -1;
643 else if (WRIGHT(wwin1) > WRIGHT(wwin2))
644 return 1;
645 else
646 return 0;
649 static int compareWBottom(const void *a, const void *b)
651 WWindow *wwin1 = *(WWindow **) a;
652 WWindow *wwin2 = *(WWindow **) b;
654 if (WBOTTOM(wwin1) < WBOTTOM(wwin2))
655 return -1;
656 else if (WBOTTOM(wwin1) > WBOTTOM(wwin2))
657 return 1;
658 else
659 return 0;
662 static void updateResistance(WWindow * wwin, MoveData * data, int newX, int newY)
664 int i;
665 int newX2 = newX + data->winWidth;
666 int newY2 = newY + data->winHeight;
667 Bool ok = False;
669 if (newX < data->realX) {
670 if (data->rightIndex > 0 && newX < WRIGHT(data->rightList[data->rightIndex - 1])) {
671 ok = True;
672 } else if (data->leftIndex <= data->count - 1 && newX2 <= WLEFT(data->leftList[data->leftIndex])) {
673 ok = True;
675 } else if (newX > data->realX) {
676 if (data->leftIndex > 0 && newX2 > WLEFT(data->leftList[data->leftIndex - 1])) {
677 ok = True;
678 } else if (data->rightIndex <= data->count - 1
679 && newX >= WRIGHT(data->rightList[data->rightIndex])) {
680 ok = True;
684 if (!ok) {
685 if (newY < data->realY) {
686 if (data->bottomIndex > 0 && newY < WBOTTOM(data->bottomList[data->bottomIndex - 1])) {
687 ok = True;
688 } else if (data->topIndex <= data->count - 1
689 && newY2 <= WTOP(data->topList[data->topIndex])) {
690 ok = True;
692 } else if (newY > data->realY) {
693 if (data->topIndex > 0 && newY2 > WTOP(data->topList[data->topIndex - 1])) {
694 ok = True;
695 } else if (data->bottomIndex <= data->count - 1
696 && newY >= WBOTTOM(data->bottomList[data->bottomIndex])) {
697 ok = True;
702 if (!ok)
703 return;
705 /* TODO: optimize this */
706 if (data->realY < WBOTTOM(data->bottomList[0])) {
707 data->bottomIndex = 0;
709 if (data->realX < WRIGHT(data->rightList[0])) {
710 data->rightIndex = 0;
712 if ((data->realX + data->winWidth) > WLEFT(data->leftList[0])) {
713 data->leftIndex = 0;
715 if ((data->realY + data->winHeight) > WTOP(data->topList[0])) {
716 data->topIndex = 0;
718 for (i = 0; i < data->count; i++) {
719 if (data->realY > WBOTTOM(data->bottomList[i])) {
720 data->bottomIndex = i + 1;
722 if (data->realX > WRIGHT(data->rightList[i])) {
723 data->rightIndex = i + 1;
725 if ((data->realX + data->winWidth) < WLEFT(data->leftList[i])) {
726 data->leftIndex = i + 1;
728 if ((data->realY + data->winHeight) < WTOP(data->topList[i])) {
729 data->topIndex = i + 1;
734 static void freeMoveData(MoveData * data)
736 if (data->topList)
737 wfree(data->topList);
738 if (data->leftList)
739 wfree(data->leftList);
740 if (data->rightList)
741 wfree(data->rightList);
742 if (data->bottomList)
743 wfree(data->bottomList);
746 static void updateMoveData(WWindow * wwin, MoveData * data)
748 WScreen *scr = wwin->screen_ptr;
749 WWindow *tmp;
750 int i;
752 data->count = 0;
753 tmp = scr->focused_window;
754 while (tmp) {
755 if (tmp != wwin && scr->current_workspace == tmp->frame->workspace
756 && !tmp->flags.miniaturized
757 && !tmp->flags.hidden && !tmp->flags.obscured && !WFLAGP(tmp, sunken)) {
758 data->topList[data->count] = tmp;
759 data->leftList[data->count] = tmp;
760 data->rightList[data->count] = tmp;
761 data->bottomList[data->count] = tmp;
762 data->count++;
764 tmp = tmp->prev;
767 if (data->count == 0) {
768 data->topIndex = 0;
769 data->leftIndex = 0;
770 data->rightIndex = 0;
771 data->bottomIndex = 0;
772 return;
775 /* order from closest to the border of the screen to farthest */
777 qsort(data->topList, data->count, sizeof(WWindow **), compareWTop);
778 qsort(data->leftList, data->count, sizeof(WWindow **), compareWLeft);
779 qsort(data->rightList, data->count, sizeof(WWindow **), compareWRight);
780 qsort(data->bottomList, data->count, sizeof(WWindow **), compareWBottom);
782 /* figure the position of the window relative to the others */
784 data->topIndex = -1;
785 data->leftIndex = -1;
786 data->rightIndex = -1;
787 data->bottomIndex = -1;
789 if (WTOP(wwin) < WBOTTOM(data->bottomList[0])) {
790 data->bottomIndex = 0;
792 if (WLEFT(wwin) < WRIGHT(data->rightList[0])) {
793 data->rightIndex = 0;
795 if (WRIGHT(wwin) > WLEFT(data->leftList[0])) {
796 data->leftIndex = 0;
798 if (WBOTTOM(wwin) > WTOP(data->topList[0])) {
799 data->topIndex = 0;
801 for (i = 0; i < data->count; i++) {
802 if (WTOP(wwin) >= WBOTTOM(data->bottomList[i])) {
803 data->bottomIndex = i + 1;
805 if (WLEFT(wwin) >= WRIGHT(data->rightList[i])) {
806 data->rightIndex = i + 1;
808 if (WRIGHT(wwin) <= WLEFT(data->leftList[i])) {
809 data->leftIndex = i + 1;
811 if (WBOTTOM(wwin) <= WTOP(data->topList[i])) {
812 data->topIndex = i + 1;
817 static void initMoveData(WWindow * wwin, MoveData * data)
819 int i;
820 WWindow *tmp;
822 memset(data, 0, sizeof(MoveData));
824 for (i = 0, tmp = wwin->screen_ptr->focused_window; tmp != NULL; tmp = tmp->prev, i++) ;
826 if (i > 1) {
827 data->topList = wmalloc(sizeof(WWindow *) * i);
828 data->leftList = wmalloc(sizeof(WWindow *) * i);
829 data->rightList = wmalloc(sizeof(WWindow *) * i);
830 data->bottomList = wmalloc(sizeof(WWindow *) * i);
832 updateMoveData(wwin, data);
835 data->realX = wwin->frame_x;
836 data->realY = wwin->frame_y;
837 data->calcX = wwin->frame_x;
838 data->calcY = wwin->frame_y;
840 data->winWidth = wwin->frame->core->width + (HAS_BORDER_WITH_SELECT(wwin) ? 2 * FRAME_BORDER_WIDTH : 0);
841 data->winHeight = wwin->frame->core->height + (HAS_BORDER_WITH_SELECT(wwin) ? 2 * FRAME_BORDER_WIDTH : 0);
844 static Bool checkWorkspaceChange(WWindow * wwin, MoveData * data, Bool opaqueMove)
846 WScreen *scr = wwin->screen_ptr;
847 Bool changed = False;
849 if (data->mouseX <= 1) {
850 if (scr->current_workspace > 0) {
852 crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace - 1, True);
853 changed = True;
854 data->rubCount = 0;
856 } else if (scr->current_workspace == 0 && wPreferences.ws_cycle) {
858 crossWorkspace(scr, wwin, opaqueMove, scr->workspace_count - 1, True);
859 changed = True;
860 data->rubCount = 0;
862 } else if (data->mouseX >= scr->scr_width - 2) {
864 if (scr->current_workspace == scr->workspace_count - 1) {
866 if (wPreferences.ws_cycle || scr->workspace_count == MAX_WORKSPACES) {
868 crossWorkspace(scr, wwin, opaqueMove, 0, False);
869 changed = True;
870 data->rubCount = 0;
872 /* if user insists on trying to go to next workspace even when
873 * it's already the last, create a new one */
874 else if (data->omouseX == data->mouseX && wPreferences.ws_advance) {
876 /* detect user "rubbing" the window against the edge */
877 if (data->rubCount > 0 && data->omouseY - data->mouseY > MOVE_THRESHOLD) {
879 data->rubCount = -(data->rubCount + 1);
881 } else if (data->rubCount <= 0 && data->mouseY - data->omouseY > MOVE_THRESHOLD) {
883 data->rubCount = -data->rubCount + 1;
886 /* create a new workspace */
887 if (abs(data->rubCount) > 2) {
888 /* go to next workspace */
889 wWorkspaceNew(scr);
891 crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace + 1, False);
892 changed = True;
893 data->rubCount = 0;
895 } else if (scr->current_workspace < scr->workspace_count) {
897 /* go to next workspace */
898 crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace + 1, False);
899 changed = True;
900 data->rubCount = 0;
902 } else {
903 data->rubCount = 0;
906 return changed;
909 static void
910 updateWindowPosition(WWindow * wwin, MoveData * data, Bool doResistance,
911 Bool opaqueMove, int newMouseX, int newMouseY)
913 WScreen *scr = wwin->screen_ptr;
914 int dx, dy; /* how much mouse moved */
915 int winL, winR, winT, winB; /* requested new window position */
916 int newX, newY; /* actual new window position */
917 Bool hresist, vresist;
918 Bool updateIndex;
919 Bool attract;
921 hresist = False;
922 vresist = False;
924 updateIndex = False;
926 /* check the direction of the movement */
927 dx = newMouseX - data->mouseX;
928 dy = newMouseY - data->mouseY;
930 data->omouseX = data->mouseX;
931 data->omouseY = data->mouseY;
932 data->mouseX = newMouseX;
933 data->mouseY = newMouseY;
935 winL = data->calcX + dx;
936 winR = data->calcX + data->winWidth + dx;
937 winT = data->calcY + dy;
938 winB = data->calcY + data->winHeight + dy;
940 newX = data->realX;
941 newY = data->realY;
943 if (doResistance) {
944 int l_edge, r_edge;
945 int edge_l, edge_r;
946 int t_edge, b_edge;
947 int edge_t, edge_b;
948 int resist;
950 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
951 attract = wPreferences.attract;
952 /* horizontal movement: check horizontal edge resistances */
953 if (dx || dy) {
954 WMRect rect;
955 int i, head;
956 /* window is the leftmost window: check against screen edge */
958 /* Add inter head resistance 1/2 (if needed) */
959 head = wGetHeadForPointerLocation(scr);
960 rect = wGetRectForHead(scr, head);
962 l_edge = WMAX(scr->totalUsableArea[head].x1, rect.pos.x);
963 edge_l = l_edge - resist;
964 edge_r = WMIN(scr->totalUsableArea[head].x2, rect.pos.x + rect.size.width);
965 r_edge = edge_r + resist;
967 /* 1 */
968 if ((data->rightIndex >= 0) && (data->rightIndex <= data->count)) {
969 WWindow *looprw;
971 for (i = data->rightIndex - 1; i >= 0; i--) {
972 looprw = data->rightList[i];
973 if (!(data->realY > WBOTTOM(looprw)
974 || (data->realY + data->winHeight) < WTOP(looprw))) {
975 if (attract || ((data->realX < (WRIGHT(looprw) + 2)) && dx < 0)) {
976 l_edge = WRIGHT(looprw) + 1;
977 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
979 break;
983 if (attract) {
984 for (i = data->rightIndex; i < data->count; i++) {
985 looprw = data->rightList[i];
986 if (!(data->realY > WBOTTOM(looprw)
987 || (data->realY + data->winHeight) < WTOP(looprw))) {
988 r_edge = WRIGHT(looprw) + 1;
989 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
990 break;
996 if ((data->leftIndex >= 0) && (data->leftIndex <= data->count)) {
997 WWindow *looprw;
999 for (i = data->leftIndex - 1; i >= 0; i--) {
1000 looprw = data->leftList[i];
1001 if (!(data->realY > WBOTTOM(looprw)
1002 || (data->realY + data->winHeight) < WTOP(looprw))) {
1003 if (attract
1004 || (((data->realX + data->winWidth) > (WLEFT(looprw) - 1))
1005 && dx > 0)) {
1006 edge_r = WLEFT(looprw);
1007 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1009 break;
1013 if (attract)
1014 for (i = data->leftIndex; i < data->count; i++) {
1015 looprw = data->leftList[i];
1016 if (!(data->realY > WBOTTOM(looprw)
1017 || (data->realY + data->winHeight) < WTOP(looprw))) {
1018 edge_l = WLEFT(looprw);
1019 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1020 break;
1026 printf("%d %d\n",winL,winR);
1027 printf("l_ %d r_ %d _l %d _r %d\n",l_edge,r_edge,edge_l,edge_r);
1030 if ((winL - l_edge) < (r_edge - winL)) {
1031 if (resist > 0) {
1032 if ((attract && winL <= l_edge + resist && winL >= l_edge - resist)
1033 || (dx < 0 && winL <= l_edge && winL >= l_edge - resist)) {
1034 newX = l_edge;
1035 hresist = True;
1038 } else {
1039 if (resist > 0 && attract && winL >= r_edge - resist && winL <= r_edge + resist) {
1040 newX = r_edge;
1041 hresist = True;
1045 if ((winR - edge_l) < (edge_r - winR)) {
1046 if (resist > 0 && attract && winR <= edge_l + resist && winR >= edge_l - resist) {
1047 newX = edge_l - data->winWidth;
1048 hresist = True;
1050 } else {
1051 if (resist > 0) {
1052 if ((attract && winR >= edge_r - resist && winR <= edge_r + resist)
1053 || (dx > 0 && winR >= edge_r && winR <= edge_r + resist)) {
1054 newX = edge_r - data->winWidth;
1055 hresist = True;
1060 /* VeRT */
1061 /* Add inter head resistance 2/2 (if needed) */
1062 t_edge = WMAX(scr->totalUsableArea[head].y1, rect.pos.y);
1063 edge_t = t_edge - resist;
1064 edge_b = WMIN(scr->totalUsableArea[head].y2, rect.pos.y + rect.size.height);
1065 b_edge = edge_b + resist;
1067 if ((data->bottomIndex >= 0) && (data->bottomIndex <= data->count)) {
1068 WWindow *looprw;
1070 for (i = data->bottomIndex - 1; i >= 0; i--) {
1071 looprw = data->bottomList[i];
1072 if (!(data->realX > WRIGHT(looprw)
1073 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1074 if (attract || ((data->realY < (WBOTTOM(looprw) + 2)) && dy < 0)) {
1075 t_edge = WBOTTOM(looprw) + 1;
1076 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1078 break;
1082 if (attract) {
1083 for (i = data->bottomIndex; i < data->count; i++) {
1084 looprw = data->bottomList[i];
1085 if (!(data->realX > WRIGHT(looprw)
1086 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1087 b_edge = WBOTTOM(looprw) + 1;
1088 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1089 break;
1095 if ((data->topIndex >= 0) && (data->topIndex <= data->count)) {
1096 WWindow *looprw;
1098 for (i = data->topIndex - 1; i >= 0; i--) {
1099 looprw = data->topList[i];
1100 if (!(data->realX > WRIGHT(looprw)
1101 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1102 if (attract
1103 || (((data->realY + data->winHeight) > (WTOP(looprw) - 1))
1104 && dy > 0)) {
1105 edge_b = WTOP(looprw);
1106 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1108 break;
1112 if (attract)
1113 for (i = data->topIndex; i < data->count; i++) {
1114 looprw = data->topList[i];
1115 if (!(data->realX > WRIGHT(looprw)
1116 || (data->realX + data->winWidth) < WLEFT(looprw))) {
1117 edge_t = WTOP(looprw);
1118 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
1119 break;
1124 if ((winT - t_edge) < (b_edge - winT)) {
1125 if (resist > 0) {
1126 if ((attract && winT <= t_edge + resist && winT >= t_edge - resist)
1127 || (dy < 0 && winT <= t_edge && winT >= t_edge - resist)) {
1128 newY = t_edge;
1129 vresist = True;
1132 } else {
1133 if (resist > 0 && attract && winT >= b_edge - resist && winT <= b_edge + resist) {
1134 newY = b_edge;
1135 vresist = True;
1139 if ((winB - edge_t) < (edge_b - winB)) {
1140 if (resist > 0 && attract && winB <= edge_t + resist && winB >= edge_t - resist) {
1141 newY = edge_t - data->winHeight;
1142 vresist = True;
1144 } else {
1145 if (resist > 0) {
1146 if ((attract && winB >= edge_b - resist && winB <= edge_b + resist)
1147 || (dy > 0 && winB >= edge_b && winB <= edge_b + resist)) {
1148 newY = edge_b - data->winHeight;
1149 vresist = True;
1154 /* END VeRT */
1158 /* update window position */
1159 data->calcX += dx;
1160 data->calcY += dy;
1162 if (((dx > 0 && data->calcX - data->realX > 0)
1163 || (dx < 0 && data->calcX - data->realX < 0)) && !hresist)
1164 newX = data->calcX;
1166 if (((dy > 0 && data->calcY - data->realY > 0)
1167 || (dy < 0 && data->calcY - data->realY < 0)) && !vresist)
1168 newY = data->calcY;
1170 if (data->realX != newX || data->realY != newY) {
1172 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1173 showPosition(wwin, data->realX, data->realY);
1175 if (opaqueMove) {
1176 doWindowMove(wwin, scr->selected_windows, newX - wwin->frame_x, newY - wwin->frame_y);
1177 } else {
1178 /* erase frames */
1179 drawFrames(wwin, scr->selected_windows,
1180 data->realX - wwin->frame_x, data->realY - wwin->frame_y);
1183 if (!scr->selected_windows && wPreferences.move_display == WDIS_FRAME_CENTER) {
1185 moveGeometryDisplayCentered(scr, newX + data->winWidth / 2, newY + data->winHeight / 2);
1188 if (!opaqueMove) {
1189 /* draw frames */
1190 drawFrames(wwin, scr->selected_windows, newX - wwin->frame_x, newY - wwin->frame_y);
1193 if (!scr->selected_windows) {
1194 showPosition(wwin, newX, newY);
1198 /* recalc relative window position */
1199 if (doResistance && (data->realX != newX || data->realY != newY)) {
1200 updateResistance(wwin, data, newX, newY);
1203 data->realX = newX;
1204 data->realY = newY;
1207 #define _KS KEY_CONTROL_WINDOW_WEIGHT
1209 #define MOVABLE_BIT 0x01
1210 #define RESIZABLE_BIT 0x02
1212 int wKeyboardMoveResizeWindow(WWindow * wwin)
1214 WScreen *scr = wwin->screen_ptr;
1215 Window root = scr->root_win;
1216 XEvent event;
1217 int w = wwin->frame->core->width;
1218 int h = wwin->frame->core->height;
1219 int scr_width = wwin->screen_ptr->scr_width;
1220 int scr_height = wwin->screen_ptr->scr_height;
1221 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1222 int src_x = wwin->frame_x;
1223 int src_y = wwin->frame_y;
1224 int done, off_x, off_y, ww, wh;
1225 int kspeed = _KS;
1226 Time lastTime = 0;
1227 KeyCode shiftl, shiftr, ctrll, ctrlmode;
1228 KeySym keysym = NoSymbol;
1229 int moment = 0;
1230 int modes = ((IS_MOVABLE(wwin) ? MOVABLE_BIT : 0) | (IS_RESIZABLE(wwin) ? RESIZABLE_BIT : 0));
1231 int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1)
1232 ? wGetHeadForWindow(wwin)
1233 : scr->xine_info.primary_head);
1235 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1236 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1237 ctrll = XKeysymToKeycode(dpy, XK_Control_L);
1238 ctrlmode = done = off_x = off_y = 0;
1240 if (modes == RESIZABLE_BIT) {
1241 ctrlmode = 1;
1244 XSync(dpy, False);
1245 wusleep(10000);
1246 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1248 if (!wwin->flags.selected) {
1249 wUnselectWindows(scr);
1251 XGrabServer(dpy);
1252 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
1253 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
1254 GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime);
1256 if (wwin->flags.shaded || scr->selected_windows) {
1257 if (scr->selected_windows)
1258 drawFrames(wwin, scr->selected_windows, off_x, off_y);
1259 else
1260 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, w, h);
1261 if (!scr->selected_windows)
1262 mapPositionDisplay(wwin, src_x, src_y, w, h);
1263 } else {
1264 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, w, h);
1266 ww = w;
1267 wh = h;
1268 while (1) {
1270 looper.ox=off_x;
1271 looper.oy=off_y;
1273 do {
1274 WMMaskEvent(dpy, KeyPressMask | ButtonReleaseMask
1275 | ButtonPressMask | ExposureMask, &event);
1276 if (event.type == Expose) {
1277 WMHandleEvent(&event);
1279 } while (event.type == Expose);
1281 if (wwin->flags.shaded || scr->selected_windows) {
1282 if (scr->selected_windows)
1283 drawFrames(wwin, scr->selected_windows, off_x, off_y);
1284 else
1285 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, w, h);
1286 /*** I HATE EDGE RESISTANCE - ]d ***/
1287 } else {
1288 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, ww, wh);
1291 if (ctrlmode)
1292 showGeometry(wwin, src_x + off_x, src_y + off_y, src_x + off_x + ww, src_y + off_y + wh,
1295 XUngrabServer(dpy);
1296 XSync(dpy, False);
1298 switch (event.type) {
1299 case KeyPress:
1300 /* accelerate */
1301 if (event.xkey.time - lastTime > 50) {
1302 kspeed /= (1 + (event.xkey.time - lastTime) / 100);
1303 } else {
1304 if (kspeed < 20) {
1305 kspeed++;
1308 if (kspeed < _KS)
1309 kspeed = _KS;
1310 lastTime = event.xkey.time;
1311 if (modes == (MOVABLE_BIT | RESIZABLE_BIT)) {
1312 if ((event.xkey.state & ControlMask) && !wwin->flags.shaded) {
1313 ctrlmode = 1;
1314 wUnselectWindows(scr);
1315 } else {
1316 ctrlmode = 0;
1319 if (event.xkey.keycode == shiftl || event.xkey.keycode == shiftr) {
1320 if (ctrlmode)
1321 cycleGeometryDisplay(wwin, src_x + off_x, src_y + off_y, ww, wh, 0);
1322 else
1323 cyclePositionDisplay(wwin, src_x + off_x, src_y + off_y, ww, wh);
1324 } else {
1326 keysym = XLookupKeysym(&event.xkey, 0);
1327 switch (keysym) {
1328 case XK_Return:
1329 done = 2;
1330 break;
1331 case XK_Escape:
1332 done = 1;
1333 break;
1334 case XK_Up:
1335 #ifdef XK_KP_Up
1336 case XK_KP_Up:
1337 #endif
1338 case XK_k:
1339 if (ctrlmode) {
1340 if (moment != UP)
1341 h = wh;
1342 h -= kspeed;
1343 moment = UP;
1344 if (h < 1)
1345 h = 1;
1346 } else
1347 off_y -= kspeed;
1348 break;
1349 case XK_Down:
1350 #ifdef XK_KP_Down
1351 case XK_KP_Down:
1352 #endif
1353 case XK_j:
1354 if (ctrlmode) {
1355 if (moment != DOWN)
1356 h = wh;
1357 h += kspeed;
1358 moment = DOWN;
1359 } else
1360 off_y += kspeed;
1361 break;
1362 case XK_Left:
1363 #ifdef XK_KP_Left
1364 case XK_KP_Left:
1365 #endif
1366 case XK_h:
1367 if (ctrlmode) {
1368 if (moment != LEFT)
1369 w = ww;
1370 w -= kspeed;
1371 if (w < 1)
1372 w = 1;
1373 moment = LEFT;
1374 } else
1375 off_x -= kspeed;
1376 break;
1377 case XK_Right:
1378 #ifdef XK_KP_Right
1379 case XK_KP_Right:
1380 #endif
1381 case XK_l:
1382 if (ctrlmode) {
1383 if (moment != RIGHT)
1384 w = ww;
1385 w += kspeed;
1386 moment = RIGHT;
1387 } else
1388 off_x += kspeed;
1389 break;
1392 ww = w;
1393 wh = h;
1394 wh -= vert_border;
1395 wWindowConstrainSize(wwin, (unsigned int *)&ww, (unsigned int *)&wh);
1396 wh += vert_border;
1398 if (wPreferences.ws_cycle) {
1399 if (src_x + off_x + ww < 20) {
1400 if (!scr->current_workspace) {
1401 wWorkspaceChange(scr, scr->workspace_count - 1);
1402 } else
1403 wWorkspaceChange(scr, scr->current_workspace - 1);
1404 off_x += scr_width;
1405 } else if (src_x + off_x + 20 > scr_width) {
1406 if (scr->current_workspace == scr->workspace_count - 1) {
1407 wWorkspaceChange(scr, 0);
1408 } else
1409 wWorkspaceChange(scr, scr->current_workspace + 1);
1410 off_x -= scr_width;
1412 } else {
1413 if (src_x + off_x + ww < 20)
1414 off_x = 20 - ww - src_x;
1415 else if (src_x + off_x + 20 > scr_width)
1416 off_x = scr_width - 20 - src_x;
1419 if (src_y + off_y + wh < 20) {
1420 off_y = 20 - wh - src_y;
1421 } else if (src_y + off_y + 20 > scr_height) {
1422 off_y = scr_height - 20 - src_y;
1425 break;
1426 case ButtonPress:
1427 case ButtonRelease:
1428 done = 1;
1429 break;
1430 case Expose:
1431 WMHandleEvent(&event);
1432 while (XCheckTypedEvent(dpy, Expose, &event)) {
1433 WMHandleEvent(&event);
1435 break;
1437 default:
1438 WMHandleEvent(&event);
1439 break;
1442 XGrabServer(dpy);
1443 /*xxx */
1445 if (wwin->flags.shaded && !scr->selected_windows) {
1446 moveGeometryDisplayCentered(scr, src_x + off_x + w / 2, src_y + off_y + h / 2);
1447 } else {
1448 if (ctrlmode) {
1449 WMUnmapWidget(scr->gview);
1450 mapGeometryDisplay(wwin, src_x + off_x, src_y + off_y, ww, wh);
1451 } else if (!scr->selected_windows) {
1452 WMUnmapWidget(scr->gview);
1453 mapPositionDisplay(wwin, src_x + off_x, src_y + off_y, ww, wh);
1457 if (wwin->flags.shaded || scr->selected_windows) {
1458 if (scr->selected_windows)
1459 drawFrames(wwin, scr->selected_windows, off_x, off_y);
1460 else
1461 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, w, h);
1462 } else {
1463 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, ww, wh);
1466 if (ctrlmode) {
1467 showGeometry(wwin, src_x + off_x, src_y + off_y, src_x + off_x + ww, src_y + off_y + wh,
1469 } else if (!scr->selected_windows)
1470 showPosition(wwin, src_x + off_x, src_y + off_y);
1472 if (done) {
1473 scr->keymove_tick = 0;
1475 WMDeleteTimerWithClientData(&looper);
1477 if (wwin->flags.shaded || scr->selected_windows) {
1478 if (scr->selected_windows)
1479 drawFrames(wwin, scr->selected_windows, off_x, off_y);
1480 else
1481 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, w, h);
1482 } else {
1483 drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, ww, wh);
1486 if (ctrlmode) {
1487 showGeometry(wwin, src_x + off_x, src_y + off_y, src_x + off_x + ww,
1488 src_y + off_y + wh, 0);
1489 WMUnmapWidget(scr->gview);
1490 } else
1491 WMUnmapWidget(scr->gview);
1493 XUngrabKeyboard(dpy, CurrentTime);
1494 XUngrabPointer(dpy, CurrentTime);
1495 XUngrabServer(dpy);
1497 if (done == 2) {
1498 if (wwin->flags.shaded || scr->selected_windows) {
1499 if (!scr->selected_windows) {
1500 wWindowMove(wwin, src_x + off_x, src_y + off_y);
1501 wWindowSynthConfigureNotify(wwin);
1502 } else {
1503 WMArrayIterator iter;
1504 WWindow *foo;
1506 doWindowMove(wwin, scr->selected_windows, off_x, off_y);
1508 WM_ITERATE_ARRAY(scr->selected_windows, foo, iter) {
1509 wWindowSynthConfigureNotify(foo);
1512 } else {
1513 if (wwin->client.width != ww) {
1514 wwin->flags.user_changed_width = 1;
1515 wwin->flags.maximized &= ~(MAX_HORIZONTAL | MAX_MAXIMUS);
1518 if (wwin->client.height != wh - vert_border) {
1519 wwin->flags.user_changed_height = 1;
1520 wwin->flags.maximized &= ~(MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS);
1523 wWindowConfigure(wwin, src_x + off_x, src_y + off_y, ww, wh - vert_border);
1524 wWindowSynthConfigureNotify(wwin);
1526 wWindowChangeWorkspace(wwin, scr->current_workspace);
1527 wSetFocusTo(scr, wwin);
1530 if (wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 &&
1531 head != wGetHeadForWindow(wwin)) {
1532 wArrangeIcons(scr, True);
1535 #if defined(VIRTUAL_DESKTOP)
1536 wWorkspaceResizeViewport(scr, scr->current_workspace);
1537 #endif
1539 return 1;
1545 *----------------------------------------------------------------------
1546 * wMouseMoveWindow--
1547 * Move the named window and the other selected ones (if any),
1548 * interactively. Also shows the position of the window, if only one
1549 * window is being moved.
1550 * If the window is not on the selected window list, the selected
1551 * windows are deselected.
1552 * If shift is pressed during the operation, the position display
1553 * is changed to another type.
1555 * Returns:
1556 * True if the window was moved, False otherwise.
1558 * Side effects:
1559 * The window(s) position is changed, and the client(s) are
1560 * notified about that.
1561 * The position display configuration may be changed.
1562 *----------------------------------------------------------------------
1564 int wMouseMoveWindow(WWindow * wwin, XEvent * ev)
1566 WScreen *scr = wwin->screen_ptr;
1567 XEvent event;
1568 Window root = scr->root_win;
1569 KeyCode shiftl, shiftr;
1570 Bool done = False;
1571 int started = 0;
1572 int warped = 0;
1573 /* This needs not to change while moving, else bad things can happen */
1574 int opaqueMove = wPreferences.opaque_move;
1575 MoveData moveData;
1576 int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1)
1577 ? wGetHeadForWindow(wwin)
1578 : scr->xine_info.primary_head);
1580 if (!IS_MOVABLE(wwin))
1581 return False;
1583 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1584 XSetWindowAttributes attr;
1586 attr.save_under = True;
1587 XChangeWindowAttributes(dpy, wwin->frame->core->window, CWSaveUnder, &attr);
1590 initMoveData(wwin, &moveData);
1592 moveData.mouseX = ev->xmotion.x_root;
1593 moveData.mouseY = ev->xmotion.y_root;
1595 if (!wwin->flags.selected) {
1596 /* this window is not selected, unselect others and move only wwin */
1597 wUnselectWindows(scr);
1599 #ifdef DEBUG
1600 puts("Moving window");
1601 #endif
1602 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1603 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1604 while (!done) {
1605 if (warped) {
1606 int junk;
1607 Window junkw;
1609 /* XWarpPointer() doesn't seem to generate Motion events, so
1610 * we've got to simulate them */
1611 XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
1612 &event.xmotion.y_root, &junk, &junk, (unsigned *)&junk);
1613 } else {
1614 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
1615 | PointerMotionHintMask
1616 | ButtonReleaseMask | ButtonPressMask | ExposureMask, &event);
1618 if (event.type == MotionNotify) {
1619 /* compress MotionNotify events */
1620 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
1621 if (!checkMouseSamplingRate(&event))
1622 continue;
1625 switch (event.type) {
1626 case KeyPress:
1627 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1628 && started && !scr->selected_windows) {
1630 if (!opaqueMove) {
1631 drawFrames(wwin, scr->selected_windows,
1632 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1635 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1636 showPosition(wwin, moveData.realX, moveData.realY);
1637 XUngrabServer(dpy);
1639 cyclePositionDisplay(wwin, moveData.realX, moveData.realY,
1640 moveData.winWidth, moveData.winHeight);
1642 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1643 XGrabServer(dpy);
1644 showPosition(wwin, moveData.realX, moveData.realY);
1647 if (!opaqueMove) {
1648 drawFrames(wwin, scr->selected_windows,
1649 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1651 /*} else {
1652 WMHandleEvent(&event); this causes problems needs fixing */
1654 break;
1656 case MotionNotify:
1657 if (started) {
1658 updateWindowPosition(wwin, &moveData,
1659 scr->selected_windows == NULL
1660 && wPreferences.edge_resistance > 0,
1661 opaqueMove, event.xmotion.x_root, event.xmotion.y_root);
1663 if (!warped && !wPreferences.no_autowrap) {
1664 int oldWorkspace = scr->current_workspace;
1666 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1667 showPosition(wwin, moveData.realX, moveData.realY);
1668 XUngrabServer(dpy);
1670 if (!opaqueMove) {
1671 drawFrames(wwin, scr->selected_windows,
1672 moveData.realX - wwin->frame_x,
1673 moveData.realY - wwin->frame_y);
1675 if (checkWorkspaceChange(wwin, &moveData, opaqueMove)) {
1676 if (scr->current_workspace != oldWorkspace
1677 && wPreferences.edge_resistance > 0
1678 && scr->selected_windows == NULL)
1679 updateMoveData(wwin, &moveData);
1680 warped = 1;
1682 if (!opaqueMove) {
1683 drawFrames(wwin, scr->selected_windows,
1684 moveData.realX - wwin->frame_x,
1685 moveData.realY - wwin->frame_y);
1687 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1688 XSync(dpy, False);
1689 showPosition(wwin, moveData.realX, moveData.realY);
1690 XGrabServer(dpy);
1692 } else {
1693 warped = 0;
1695 } else if (abs(ev->xmotion.x_root - event.xmotion.x_root) >= MOVE_THRESHOLD
1696 || abs(ev->xmotion.y_root - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1698 XChangeActivePointerGrab(dpy, ButtonMotionMask
1699 | ButtonReleaseMask | ButtonPressMask,
1700 wCursor[WCUR_MOVE], CurrentTime);
1701 started = 1;
1702 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1704 if (!scr->selected_windows)
1705 mapPositionDisplay(wwin, moveData.realX, moveData.realY,
1706 moveData.winWidth, moveData.winHeight);
1708 if (started && !opaqueMove)
1709 drawFrames(wwin, scr->selected_windows, 0, 0);
1711 if (!opaqueMove || (wPreferences.move_display == WDIS_NEW
1712 && !scr->selected_windows)) {
1713 XGrabServer(dpy);
1714 if (wPreferences.move_display == WDIS_NEW)
1715 showPosition(wwin, moveData.realX, moveData.realY);
1718 break;
1720 case ButtonPress:
1721 break;
1723 case ButtonRelease:
1724 if (event.xbutton.button != ev->xbutton.button)
1725 break;
1727 if (started) {
1728 XEvent e;
1729 if (!opaqueMove) {
1730 drawFrames(wwin, scr->selected_windows,
1731 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1732 XSync(dpy, 0);
1733 doWindowMove(wwin, scr->selected_windows,
1734 moveData.realX - wwin->frame_x,
1735 moveData.realY - wwin->frame_y);
1737 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
1738 wWindowSynthConfigureNotify(wwin);
1739 #endif
1740 XUngrabKeyboard(dpy, CurrentTime);
1741 XUngrabServer(dpy);
1742 if (!opaqueMove) {
1743 wWindowChangeWorkspace(wwin, scr->current_workspace);
1744 wSetFocusTo(scr, wwin);
1746 if (wPreferences.move_display == WDIS_NEW)
1747 showPosition(wwin, moveData.realX, moveData.realY);
1749 /* discard all enter/leave events that happened until
1750 * the time the button was released */
1751 while (XCheckTypedEvent(dpy, EnterNotify, &e)) {
1752 if (e.xcrossing.time > event.xbutton.time) {
1753 XPutBackEvent(dpy, &e);
1754 break;
1757 while (XCheckTypedEvent(dpy, LeaveNotify, &e)) {
1758 if (e.xcrossing.time > event.xbutton.time) {
1759 XPutBackEvent(dpy, &e);
1760 break;
1764 if (!scr->selected_windows) {
1765 /* get rid of the geometry window */
1766 WMUnmapWidget(scr->gview);
1769 #ifdef DEBUG
1770 puts("End move window");
1771 #endif
1772 done = True;
1773 break;
1775 default:
1776 if (started && !opaqueMove) {
1777 drawFrames(wwin, scr->selected_windows,
1778 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1779 XUngrabServer(dpy);
1780 WMHandleEvent(&event);
1781 XSync(dpy, False);
1782 XGrabServer(dpy);
1783 drawFrames(wwin, scr->selected_windows,
1784 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1785 } else {
1786 WMHandleEvent(&event);
1788 break;
1792 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1793 XSetWindowAttributes attr;
1795 attr.save_under = False;
1796 XChangeWindowAttributes(dpy, wwin->frame->core->window, CWSaveUnder, &attr);
1800 freeMoveData(&moveData);
1802 if (started && wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 &&
1803 head != wGetHeadForWindow(wwin)) {
1804 wArrangeIcons(scr, True);
1806 #if defined(VIRTUAL_DESKTOP)
1807 if (started)
1808 wWorkspaceResizeViewport(scr, scr->current_workspace);
1809 #endif
1811 return started;
1814 #define RESIZEBAR 1
1815 #define HCONSTRAIN 2
1817 static int getResizeDirection(WWindow * wwin, int x, int y, int dx, int dy, int flags)
1819 int w = wwin->frame->core->width - 1;
1820 int cw = wwin->frame->resizebar_corner_width;
1821 int dir;
1823 /* if not resizing through the resizebar */
1824 if (!(flags & RESIZEBAR)) {
1825 int xdir = (abs(x) < (wwin->client.width / 2)) ? LEFT : RIGHT;
1826 int ydir = (abs(y) < (wwin->client.height / 2)) ? UP : DOWN;
1827 if (abs(dx) < 2 || abs(dy) < 2) {
1828 if (abs(dy) > abs(dx))
1829 xdir = 0;
1830 else
1831 ydir = 0;
1833 return (xdir | ydir);
1836 /* window is too narrow. allow diagonal resize */
1837 if (cw * 2 >= w) {
1838 int ydir;
1840 if (flags & HCONSTRAIN)
1841 ydir = 0;
1842 else
1843 ydir = DOWN;
1844 if (x < cw)
1845 return (LEFT | ydir);
1846 else
1847 return (RIGHT | ydir);
1849 /* vertical resize */
1850 if ((x > cw) && (x < w - cw))
1851 return DOWN;
1853 if (x < cw)
1854 dir = LEFT;
1855 else
1856 dir = RIGHT;
1858 if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
1859 dir |= DOWN;
1861 return dir;
1864 void wMouseResizeWindow(WWindow * wwin, XEvent * ev)
1866 XEvent event;
1867 WScreen *scr = wwin->screen_ptr;
1868 Window root = scr->root_win;
1869 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1870 int fw = wwin->frame->core->width;
1871 int fh = wwin->frame->core->height;
1872 int fx = wwin->frame_x;
1873 int fy = wwin->frame_y;
1874 int is_resizebar = (wwin->frame->resizebar && ev->xany.window == wwin->frame->resizebar->window);
1875 int orig_x, orig_y;
1876 int started;
1877 int dw, dh;
1878 int rw = fw, rh = fh;
1879 int rx1, ry1, rx2, ry2;
1880 int res = 0;
1881 KeyCode shiftl, shiftr;
1882 int h = 0;
1883 int orig_fx = fx;
1884 int orig_fy = fy;
1885 int orig_fw = fw;
1886 int orig_fh = fh;
1887 int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1)
1888 ? wGetHeadForWindow(wwin)
1889 : scr->xine_info.primary_head);
1891 if (!IS_RESIZABLE(wwin))
1892 return;
1894 if (wwin->flags.shaded) {
1895 wwarning("internal error: tryein");
1896 return;
1898 orig_x = ev->xbutton.x_root;
1899 orig_y = ev->xbutton.y_root;
1901 started = 0;
1902 #ifdef DEBUG
1903 puts("Resizing window");
1904 #endif
1906 wUnselectWindows(scr);
1907 rx1 = fx;
1908 rx2 = fx + fw - 1;
1909 ry1 = fy;
1910 ry2 = fy + fh - 1;
1911 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1912 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1913 if (HAS_TITLEBAR(wwin))
1914 h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance +
1915 TITLEBAR_EXTEND_SPACE) * 2;
1916 else
1917 h = 0;
1918 while (1) {
1919 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
1920 | ButtonReleaseMask | PointerMotionHintMask | ButtonPressMask | ExposureMask, &event);
1921 if (!checkMouseSamplingRate(&event))
1922 continue;
1924 switch (event.type) {
1925 case KeyPress:
1926 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1927 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1928 && started) {
1929 drawTransparentFrame(wwin, fx, fy, fw, fh);
1930 cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
1931 drawTransparentFrame(wwin, fx, fy, fw, fh);
1933 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1934 break;
1936 case MotionNotify:
1937 if (started) {
1938 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
1940 dw = 0;
1941 dh = 0;
1943 orig_fx = fx;
1944 orig_fy = fy;
1945 orig_fw = fw;
1946 orig_fh = fh;
1948 if (res & LEFT)
1949 dw = orig_x - event.xmotion.x_root;
1950 else if (res & RIGHT)
1951 dw = event.xmotion.x_root - orig_x;
1952 if (res & UP)
1953 dh = orig_y - event.xmotion.y_root;
1954 else if (res & DOWN)
1955 dh = event.xmotion.y_root - orig_y;
1957 orig_x = event.xmotion.x_root;
1958 orig_y = event.xmotion.y_root;
1960 rw += dw;
1961 rh += dh;
1962 fw = rw;
1963 fh = rh - vert_border;
1964 wWindowConstrainSize(wwin, (unsigned int *)&fw, (unsigned int *)&fh);
1965 fh += vert_border;
1966 if (res & LEFT)
1967 fx = rx2 - fw + 1;
1968 else if (res & RIGHT)
1969 fx = rx1;
1970 if (res & UP)
1971 fy = ry2 - fh + 1;
1972 else if (res & DOWN)
1973 fy = ry1;
1974 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
1975 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1976 int tx, ty;
1977 Window junkw;
1978 int flags;
1980 XTranslateCoordinates(dpy, root, wwin->frame->core->window,
1981 orig_x, orig_y, &tx, &ty, &junkw);
1983 /* check if resizing through resizebar */
1984 if (is_resizebar)
1985 flags = RESIZEBAR;
1986 else
1987 flags = 0;
1989 if (is_resizebar && ((ev->xbutton.state & ShiftMask)
1990 || abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
1991 flags |= HCONSTRAIN;
1993 res = getResizeDirection(wwin, tx, ty,
1994 orig_x - event.xmotion.x_root,
1995 orig_y - event.xmotion.y_root, flags);
1997 if (res == (UP | LEFT))
1998 XChangeActivePointerGrab(dpy, ButtonMotionMask
1999 | ButtonReleaseMask | ButtonPressMask,
2000 wCursor[WCUR_TOPLEFTRESIZE], CurrentTime);
2001 else if (res == (UP | RIGHT))
2002 XChangeActivePointerGrab(dpy, ButtonMotionMask
2003 | ButtonReleaseMask | ButtonPressMask,
2004 wCursor[WCUR_TOPRIGHTRESIZE], CurrentTime);
2005 else if (res == (DOWN | LEFT))
2006 XChangeActivePointerGrab(dpy, ButtonMotionMask
2007 | ButtonReleaseMask | ButtonPressMask,
2008 wCursor[WCUR_BOTTOMLEFTRESIZE], CurrentTime);
2009 else if (res == (DOWN | RIGHT))
2010 XChangeActivePointerGrab(dpy, ButtonMotionMask
2011 | ButtonReleaseMask | ButtonPressMask,
2012 wCursor[WCUR_BOTTOMRIGHTRESIZE], CurrentTime);
2013 else if (res == DOWN || res == UP)
2014 XChangeActivePointerGrab(dpy, ButtonMotionMask
2015 | ButtonReleaseMask | ButtonPressMask,
2016 wCursor[WCUR_VERTICALRESIZE], CurrentTime);
2017 else if (res & (DOWN | UP))
2018 XChangeActivePointerGrab(dpy, ButtonMotionMask
2019 | ButtonReleaseMask | ButtonPressMask,
2020 wCursor[WCUR_VERTICALRESIZE], CurrentTime);
2021 else if (res & (LEFT | RIGHT))
2022 XChangeActivePointerGrab(dpy, ButtonMotionMask
2023 | ButtonReleaseMask | ButtonPressMask,
2024 wCursor[WCUR_HORIZONRESIZE], CurrentTime);
2026 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
2028 XGrabServer(dpy);
2030 /* Draw the resize frame for the first time. */
2031 mapGeometryDisplay(wwin, fx, fy, fw, fh);
2033 drawTransparentFrame(wwin, fx, fy, fw, fh);
2035 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2037 started = 1;
2039 if (started) {
2040 if (wPreferences.size_display == WDIS_FRAME_CENTER) {
2041 drawTransparentFrame(wwin, orig_fx, orig_fy, orig_fw, orig_fh);
2042 moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
2043 drawTransparentFrame(wwin, fx, fy, fw, fh);
2044 } else {
2045 drawTransparentFrame(wwin, orig_fx, orig_fy, orig_fw, orig_fh);
2046 drawTransparentFrame(wwin, fx, fy, fw, fh);
2048 if (fh != orig_fh || fw != orig_fw) {
2049 if (wPreferences.size_display == WDIS_NEW) {
2050 showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw,
2051 orig_fy + orig_fh, res);
2053 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2056 break;
2058 case ButtonPress:
2059 break;
2061 case ButtonRelease:
2062 if (event.xbutton.button != ev->xbutton.button)
2063 break;
2065 if (started) {
2066 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2068 drawTransparentFrame(wwin, fx, fy, fw, fh);
2070 XUngrabKeyboard(dpy, CurrentTime);
2071 WMUnmapWidget(scr->gview);
2072 XUngrabServer(dpy);
2074 if (wwin->client.width != fw) {
2075 wwin->flags.user_changed_width = 1;
2076 wwin->flags.maximized &= ~(MAX_HORIZONTAL | MAX_MAXIMUS);
2079 if (wwin->client.height != fh - vert_border) {
2080 wwin->flags.user_changed_height = 1;
2081 wwin->flags.maximized &= ~(MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS);
2084 wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
2086 #ifdef DEBUG
2087 puts("End resize window");
2088 #endif
2089 return;
2091 default:
2092 WMHandleEvent(&event);
2096 if (wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 && head != wGetHeadForWindow(wwin)) {
2097 wArrangeIcons(scr, True);
2099 #if defined(VIRTUAL_DESKTOP)
2100 wWorkspaceResizeViewport(scr, scr->current_workspace);
2101 #endif
2104 #undef LEFT
2105 #undef RIGHT
2106 #undef HORIZONTAL
2107 #undef UP
2108 #undef DOWN
2109 #undef VERTICAL
2110 #undef HCONSTRAIN
2111 #undef RESIZEBAR
2113 void wUnselectWindows(WScreen * scr)
2115 WWindow *wwin;
2117 if (!scr->selected_windows)
2118 return;
2120 while (WMGetArrayItemCount(scr->selected_windows)) {
2121 wwin = WMGetFromArray(scr->selected_windows, 0);
2122 if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
2123 wIconSelect(wwin->icon);
2125 wSelectWindow(wwin, False);
2127 WMFreeArray(scr->selected_windows);
2128 scr->selected_windows = NULL;
2131 static void selectWindowsInside(WScreen * scr, int x1, int y1, int x2, int y2)
2133 WWindow *tmpw;
2135 /* select the windows and put them in the selected window list */
2136 tmpw = scr->focused_window;
2137 while (tmpw != NULL) {
2138 if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
2139 if ((tmpw->frame->workspace == scr->current_workspace || IS_OMNIPRESENT(tmpw))
2140 && (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1)
2141 && (tmpw->frame->core->width + tmpw->frame_x <= x2)
2142 && (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
2143 wSelectWindow(tmpw, True);
2146 tmpw = tmpw->prev;
2150 void wSelectWindows(WScreen * scr, XEvent * ev)
2152 XEvent event;
2153 Window root = scr->root_win;
2154 GC gc = scr->frame_gc;
2155 int xp = ev->xbutton.x_root;
2156 int yp = ev->xbutton.y_root;
2157 int w = 0, h = 0;
2158 int x = xp, y = yp;
2160 #ifdef DEBUG
2161 puts("Selecting windows");
2162 #endif
2163 if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
2164 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
2165 GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
2166 return;
2168 XGrabServer(dpy);
2170 wUnselectWindows(scr);
2172 XDrawRectangle(dpy, root, gc, xp, yp, w, h);
2173 while (1) {
2174 WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask | ButtonPressMask, &event);
2176 switch (event.type) {
2177 case MotionNotify:
2178 XDrawRectangle(dpy, root, gc, x, y, w, h);
2179 x = event.xmotion.x_root;
2180 if (x < xp) {
2181 w = xp - x;
2182 } else {
2183 w = x - xp;
2184 x = xp;
2186 y = event.xmotion.y_root;
2187 if (y < yp) {
2188 h = yp - y;
2189 } else {
2190 h = y - yp;
2191 y = yp;
2193 XDrawRectangle(dpy, root, gc, x, y, w, h);
2194 break;
2196 case ButtonPress:
2197 break;
2199 case ButtonRelease:
2200 if (event.xbutton.button != ev->xbutton.button)
2201 break;
2203 XDrawRectangle(dpy, root, gc, x, y, w, h);
2204 XUngrabServer(dpy);
2205 XUngrabPointer(dpy, CurrentTime);
2206 selectWindowsInside(scr, x, y, x + w, y + h);
2208 #ifdef DEBUG
2209 puts("End window selection");
2210 #endif
2211 return;
2213 default:
2214 WMHandleEvent(&event);
2215 break;
2220 void InteractivePlaceWindow(WWindow * wwin, int *x_ret, int *y_ret, unsigned width, unsigned height)
2222 WScreen *scr = wwin->screen_ptr;
2223 Window root = scr->root_win;
2224 int x, y, h = 0;
2225 XEvent event;
2226 KeyCode shiftl, shiftr;
2227 Window junkw;
2228 int junk;
2230 if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
2231 GrabModeAsync, GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
2232 *x_ret = 0;
2233 *y_ret = 0;
2234 return;
2236 if (HAS_TITLEBAR(wwin)) {
2237 h = WMFontHeight(scr->title_font) + (wPreferences.window_title_clearance +
2238 TITLEBAR_EXTEND_SPACE) * 2;
2239 height += h;
2241 if (HAS_RESIZEBAR(wwin)) {
2242 height += RESIZEBAR_HEIGHT;
2244 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
2245 XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk, (unsigned *)&junk);
2246 mapPositionDisplay(wwin, x - width / 2, y - h / 2, width, height);
2248 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2250 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
2251 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
2252 while (1) {
2253 WMMaskEvent(dpy, PointerMotionMask | ButtonPressMask | ExposureMask | KeyPressMask, &event);
2255 if (!checkMouseSamplingRate(&event))
2256 continue;
2258 switch (event.type) {
2259 case KeyPress:
2260 if ((event.xkey.keycode == shiftl)
2261 || (event.xkey.keycode == shiftr)) {
2262 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2263 cyclePositionDisplay(wwin, x - width / 2, y - h / 2, width, height);
2264 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2266 break;
2268 case MotionNotify:
2269 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2271 x = event.xmotion.x_root;
2272 y = event.xmotion.y_root;
2274 if (wPreferences.move_display == WDIS_FRAME_CENTER)
2275 moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
2277 showPosition(wwin, x - width / 2, y - h / 2);
2279 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2281 break;
2283 case ButtonPress:
2284 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2285 XSync(dpy, 0);
2286 *x_ret = x - width / 2;
2287 *y_ret = y - h / 2;
2288 XUngrabPointer(dpy, CurrentTime);
2289 XUngrabKeyboard(dpy, CurrentTime);
2290 /* get rid of the geometry window */
2291 WMUnmapWidget(scr->gview);
2292 return;
2294 default:
2295 WMHandleEvent(&event);
2296 break;