Change to the linux kernel coding style
[wmaker-crm.git] / src / moveres.c
blobb0d4a467628c4aeea86c1ec0c8a7ed59f8753de0
1 /*
2 * Window Maker window manager
3 *
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
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.
15 *
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.
20 */
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
62 */
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;
74 /*
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 *----------------------------------------------------------------------
81 */
82 static Bool checkMouseSamplingRate(XEvent * ev)
83 {
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;
91 }
92 }
93 return True;
94 }
96 /*
97 *----------------------------------------------------------------------
98 * moveGeometryDisplayCentered
99 *
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 *----------------------------------------------------------------------
104 */
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;
1025 /*
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);
1028 */
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) {
1269 /*
1270 looper.ox=off_x;
1271 looper.oy=off_y;
1272 */
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,
1293 0);
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,
1468 0);
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;
1474 /*
1475 WMDeleteTimerWithClientData(&looper);
1476 */
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;
1516 if (wwin->client.height != wh - vert_border)
1517 wwin->flags.user_changed_height = 1;
1519 wWindowConfigure(wwin, src_x + off_x, src_y + off_y, ww, wh - vert_border);
1520 wWindowSynthConfigureNotify(wwin);
1522 wWindowChangeWorkspace(wwin, scr->current_workspace);
1523 wSetFocusTo(scr, wwin);
1526 if (wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 &&
1527 head != wGetHeadForWindow(wwin)) {
1528 wArrangeIcons(scr, True);
1531 #if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP)
1532 wWorkspaceResizeViewport(scr, scr->current_workspace);
1533 #endif
1535 return 1;
1540 /*
1541 *----------------------------------------------------------------------
1542 * wMouseMoveWindow--
1543 * Move the named window and the other selected ones (if any),
1544 * interactively. Also shows the position of the window, if only one
1545 * window is being moved.
1546 * If the window is not on the selected window list, the selected
1547 * windows are deselected.
1548 * If shift is pressed during the operation, the position display
1549 * is changed to another type.
1551 * Returns:
1552 * True if the window was moved, False otherwise.
1554 * Side effects:
1555 * The window(s) position is changed, and the client(s) are
1556 * notified about that.
1557 * The position display configuration may be changed.
1558 *----------------------------------------------------------------------
1559 */
1560 int wMouseMoveWindow(WWindow * wwin, XEvent * ev)
1562 WScreen *scr = wwin->screen_ptr;
1563 XEvent event;
1564 Window root = scr->root_win;
1565 KeyCode shiftl, shiftr;
1566 Bool done = False;
1567 int started = 0;
1568 int warped = 0;
1569 /* This needs not to change while moving, else bad things can happen */
1570 int opaqueMove = wPreferences.opaque_move;
1571 MoveData moveData;
1572 int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1)
1573 ? wGetHeadForWindow(wwin)
1574 : scr->xine_info.primary_head);
1575 #ifdef GHOST_WINDOW_MOVE
1576 RImage *rimg = InitGhostWindowMove(scr);
1577 #endif
1579 if (!IS_MOVABLE(wwin))
1580 return False;
1582 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1583 XSetWindowAttributes attr;
1585 attr.save_under = True;
1586 XChangeWindowAttributes(dpy, wwin->frame->core->window, CWSaveUnder, &attr);
1589 initMoveData(wwin, &moveData);
1591 moveData.mouseX = ev->xmotion.x_root;
1592 moveData.mouseY = ev->xmotion.y_root;
1594 if (!wwin->flags.selected) {
1595 /* this window is not selected, unselect others and move only wwin */
1596 wUnselectWindows(scr);
1598 #ifdef DEBUG
1599 puts("Moving window");
1600 #endif
1601 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1602 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1603 while (!done) {
1604 if (warped) {
1605 int junk;
1606 Window junkw;
1608 /* XWarpPointer() doesn't seem to generate Motion events, so
1609 * we've got to simulate them */
1610 XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
1611 &event.xmotion.y_root, &junk, &junk, (unsigned *)&junk);
1612 } else {
1613 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
1614 | PointerMotionHintMask
1615 | ButtonReleaseMask | ButtonPressMask | ExposureMask, &event);
1617 if (event.type == MotionNotify) {
1618 /* compress MotionNotify events */
1619 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
1620 if (!checkMouseSamplingRate(&event))
1621 continue;
1624 switch (event.type) {
1625 case KeyPress:
1626 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1627 && started && !scr->selected_windows) {
1629 if (!opaqueMove) {
1630 drawFrames(wwin, scr->selected_windows,
1631 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1634 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1635 showPosition(wwin, moveData.realX, moveData.realY);
1636 XUngrabServer(dpy);
1638 cyclePositionDisplay(wwin, moveData.realX, moveData.realY,
1639 moveData.winWidth, moveData.winHeight);
1641 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1642 XGrabServer(dpy);
1643 showPosition(wwin, moveData.realX, moveData.realY);
1646 if (!opaqueMove) {
1647 drawFrames(wwin, scr->selected_windows,
1648 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1650 /*} else {
1651 WMHandleEvent(&event); this causes problems needs fixing */
1653 break;
1655 case MotionNotify:
1656 if (started) {
1657 updateWindowPosition(wwin, &moveData,
1658 scr->selected_windows == NULL
1659 && wPreferences.edge_resistance > 0,
1660 opaqueMove, event.xmotion.x_root, event.xmotion.y_root);
1662 if (!warped && !wPreferences.no_autowrap) {
1663 int oldWorkspace = scr->current_workspace;
1665 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1666 showPosition(wwin, moveData.realX, moveData.realY);
1667 XUngrabServer(dpy);
1669 if (!opaqueMove) {
1670 drawFrames(wwin, scr->selected_windows,
1671 moveData.realX - wwin->frame_x,
1672 moveData.realY - wwin->frame_y);
1674 if (checkWorkspaceChange(wwin, &moveData, opaqueMove)) {
1675 if (scr->current_workspace != oldWorkspace
1676 && wPreferences.edge_resistance > 0
1677 && scr->selected_windows == NULL)
1678 updateMoveData(wwin, &moveData);
1679 warped = 1;
1681 if (!opaqueMove) {
1682 drawFrames(wwin, scr->selected_windows,
1683 moveData.realX - wwin->frame_x,
1684 moveData.realY - wwin->frame_y);
1686 if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
1687 XSync(dpy, False);
1688 showPosition(wwin, moveData.realX, moveData.realY);
1689 XGrabServer(dpy);
1691 } else {
1692 warped = 0;
1694 } else if (abs(ev->xmotion.x_root - event.xmotion.x_root) >= MOVE_THRESHOLD
1695 || abs(ev->xmotion.y_root - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1697 XChangeActivePointerGrab(dpy, ButtonMotionMask
1698 | ButtonReleaseMask | ButtonPressMask,
1699 wCursor[WCUR_MOVE], CurrentTime);
1700 started = 1;
1701 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1703 if (!scr->selected_windows)
1704 mapPositionDisplay(wwin, moveData.realX, moveData.realY,
1705 moveData.winWidth, moveData.winHeight);
1707 if (started && !opaqueMove)
1708 drawFrames(wwin, scr->selected_windows, 0, 0);
1710 if (!opaqueMove || (wPreferences.move_display == WDIS_NEW
1711 && !scr->selected_windows)) {
1712 XGrabServer(dpy);
1713 if (wPreferences.move_display == WDIS_NEW)
1714 showPosition(wwin, moveData.realX, moveData.realY);
1717 break;
1719 case ButtonPress:
1720 break;
1722 case ButtonRelease:
1723 if (event.xbutton.button != ev->xbutton.button)
1724 break;
1726 if (started) {
1727 XEvent e;
1728 if (!opaqueMove) {
1729 drawFrames(wwin, scr->selected_windows,
1730 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1731 XSync(dpy, 0);
1732 doWindowMove(wwin, scr->selected_windows,
1733 moveData.realX - wwin->frame_x,
1734 moveData.realY - wwin->frame_y);
1736 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
1737 wWindowSynthConfigureNotify(wwin);
1738 #endif
1739 XUngrabKeyboard(dpy, CurrentTime);
1740 XUngrabServer(dpy);
1741 if (!opaqueMove) {
1742 wWindowChangeWorkspace(wwin, scr->current_workspace);
1743 wSetFocusTo(scr, wwin);
1745 if (wPreferences.move_display == WDIS_NEW)
1746 showPosition(wwin, moveData.realX, moveData.realY);
1748 /* discard all enter/leave events that happened until
1749 * the time the button was released */
1750 while (XCheckTypedEvent(dpy, EnterNotify, &e)) {
1751 if (e.xcrossing.time > event.xbutton.time) {
1752 XPutBackEvent(dpy, &e);
1753 break;
1756 while (XCheckTypedEvent(dpy, LeaveNotify, &e)) {
1757 if (e.xcrossing.time > event.xbutton.time) {
1758 XPutBackEvent(dpy, &e);
1759 break;
1763 if (!scr->selected_windows) {
1764 /* get rid of the geometry window */
1765 WMUnmapWidget(scr->gview);
1768 #ifdef DEBUG
1769 puts("End move window");
1770 #endif
1771 done = True;
1772 break;
1774 default:
1775 if (started && !opaqueMove) {
1776 drawFrames(wwin, scr->selected_windows,
1777 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1778 XUngrabServer(dpy);
1779 WMHandleEvent(&event);
1780 XSync(dpy, False);
1781 XGrabServer(dpy);
1782 drawFrames(wwin, scr->selected_windows,
1783 moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
1784 } else {
1785 WMHandleEvent(&event);
1787 break;
1791 if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
1792 XSetWindowAttributes attr;
1794 attr.save_under = False;
1795 XChangeWindowAttributes(dpy, wwin->frame->core->window, CWSaveUnder, &attr);
1799 freeMoveData(&moveData);
1801 if (started && wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 &&
1802 head != wGetHeadForWindow(wwin)) {
1803 wArrangeIcons(scr, True);
1805 #if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP)
1806 if (started)
1807 wWorkspaceResizeViewport(scr, scr->current_workspace);
1808 #endif
1810 return started;
1813 #define RESIZEBAR 1
1814 #define HCONSTRAIN 2
1816 static int getResizeDirection(WWindow * wwin, int x, int y, int dx, int dy, int flags)
1818 int w = wwin->frame->core->width - 1;
1819 int cw = wwin->frame->resizebar_corner_width;
1820 int dir;
1822 /* if not resizing through the resizebar */
1823 if (!(flags & RESIZEBAR)) {
1824 int xdir = (abs(x) < (wwin->client.width / 2)) ? LEFT : RIGHT;
1825 int ydir = (abs(y) < (wwin->client.height / 2)) ? UP : DOWN;
1826 if (abs(dx) < 2 || abs(dy) < 2) {
1827 if (abs(dy) > abs(dx))
1828 xdir = 0;
1829 else
1830 ydir = 0;
1832 return (xdir | ydir);
1835 /* window is too narrow. allow diagonal resize */
1836 if (cw * 2 >= w) {
1837 int ydir;
1839 if (flags & HCONSTRAIN)
1840 ydir = 0;
1841 else
1842 ydir = DOWN;
1843 if (x < cw)
1844 return (LEFT | ydir);
1845 else
1846 return (RIGHT | ydir);
1848 /* vertical resize */
1849 if ((x > cw) && (x < w - cw))
1850 return DOWN;
1852 if (x < cw)
1853 dir = LEFT;
1854 else
1855 dir = RIGHT;
1857 if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
1858 dir |= DOWN;
1860 return dir;
1863 void wMouseResizeWindow(WWindow * wwin, XEvent * ev)
1865 XEvent event;
1866 WScreen *scr = wwin->screen_ptr;
1867 Window root = scr->root_win;
1868 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1869 int fw = wwin->frame->core->width;
1870 int fh = wwin->frame->core->height;
1871 int fx = wwin->frame_x;
1872 int fy = wwin->frame_y;
1873 int is_resizebar = (wwin->frame->resizebar && ev->xany.window == wwin->frame->resizebar->window);
1874 int orig_x, orig_y;
1875 int started;
1876 int dw, dh;
1877 int rw = fw, rh = fh;
1878 int rx1, ry1, rx2, ry2;
1879 int res = 0;
1880 KeyCode shiftl, shiftr;
1881 int h = 0;
1882 int orig_fx = fx;
1883 int orig_fy = fy;
1884 int orig_fw = fw;
1885 int orig_fh = fh;
1886 int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1)
1887 ? wGetHeadForWindow(wwin)
1888 : scr->xine_info.primary_head);
1890 if (!IS_RESIZABLE(wwin))
1891 return;
1893 if (wwin->flags.shaded) {
1894 wwarning("internal error: tryein");
1895 return;
1897 orig_x = ev->xbutton.x_root;
1898 orig_y = ev->xbutton.y_root;
1900 started = 0;
1901 #ifdef DEBUG
1902 puts("Resizing window");
1903 #endif
1905 wUnselectWindows(scr);
1906 rx1 = fx;
1907 rx2 = fx + fw - 1;
1908 ry1 = fy;
1909 ry2 = fy + fh - 1;
1910 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1911 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1912 if (HAS_TITLEBAR(wwin))
1913 h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance +
1914 TITLEBAR_EXTEND_SPACE) * 2;
1915 else
1916 h = 0;
1917 while (1) {
1918 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
1919 | ButtonReleaseMask | PointerMotionHintMask | ButtonPressMask | ExposureMask, &event);
1920 if (!checkMouseSamplingRate(&event))
1921 continue;
1923 switch (event.type) {
1924 case KeyPress:
1925 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1926 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1927 && started) {
1928 drawTransparentFrame(wwin, fx, fy, fw, fh);
1929 cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
1930 drawTransparentFrame(wwin, fx, fy, fw, fh);
1932 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1933 break;
1935 case MotionNotify:
1936 if (started) {
1937 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
1939 dw = 0;
1940 dh = 0;
1942 orig_fx = fx;
1943 orig_fy = fy;
1944 orig_fw = fw;
1945 orig_fh = fh;
1947 if (res & LEFT)
1948 dw = orig_x - event.xmotion.x_root;
1949 else if (res & RIGHT)
1950 dw = event.xmotion.x_root - orig_x;
1951 if (res & UP)
1952 dh = orig_y - event.xmotion.y_root;
1953 else if (res & DOWN)
1954 dh = event.xmotion.y_root - orig_y;
1956 orig_x = event.xmotion.x_root;
1957 orig_y = event.xmotion.y_root;
1959 rw += dw;
1960 rh += dh;
1961 fw = rw;
1962 fh = rh - vert_border;
1963 wWindowConstrainSize(wwin, (unsigned int *)&fw, (unsigned int *)&fh);
1964 fh += vert_border;
1965 if (res & LEFT)
1966 fx = rx2 - fw + 1;
1967 else if (res & RIGHT)
1968 fx = rx1;
1969 if (res & UP)
1970 fy = ry2 - fh + 1;
1971 else if (res & DOWN)
1972 fy = ry1;
1973 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
1974 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1975 int tx, ty;
1976 Window junkw;
1977 int flags;
1979 XTranslateCoordinates(dpy, root, wwin->frame->core->window,
1980 orig_x, orig_y, &tx, &ty, &junkw);
1982 /* check if resizing through resizebar */
1983 if (is_resizebar)
1984 flags = RESIZEBAR;
1985 else
1986 flags = 0;
1988 if (is_resizebar && ((ev->xbutton.state & ShiftMask)
1989 || abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
1990 flags |= HCONSTRAIN;
1992 res = getResizeDirection(wwin, tx, ty,
1993 orig_x - event.xmotion.x_root,
1994 orig_y - event.xmotion.y_root, flags);
1996 if (res == (UP | LEFT))
1997 XChangeActivePointerGrab(dpy, ButtonMotionMask
1998 | ButtonReleaseMask | ButtonPressMask,
1999 wCursor[WCUR_TOPLEFTRESIZE], CurrentTime);
2000 else if (res == (UP | RIGHT))
2001 XChangeActivePointerGrab(dpy, ButtonMotionMask
2002 | ButtonReleaseMask | ButtonPressMask,
2003 wCursor[WCUR_TOPRIGHTRESIZE], CurrentTime);
2004 else if (res == (DOWN | LEFT))
2005 XChangeActivePointerGrab(dpy, ButtonMotionMask
2006 | ButtonReleaseMask | ButtonPressMask,
2007 wCursor[WCUR_BOTTOMLEFTRESIZE], CurrentTime);
2008 else if (res == (DOWN | RIGHT))
2009 XChangeActivePointerGrab(dpy, ButtonMotionMask
2010 | ButtonReleaseMask | ButtonPressMask,
2011 wCursor[WCUR_BOTTOMRIGHTRESIZE], CurrentTime);
2012 else if (res == DOWN || res == UP)
2013 XChangeActivePointerGrab(dpy, ButtonMotionMask
2014 | ButtonReleaseMask | ButtonPressMask,
2015 wCursor[WCUR_VERTICALRESIZE], CurrentTime);
2016 else if (res & (DOWN | UP))
2017 XChangeActivePointerGrab(dpy, ButtonMotionMask
2018 | ButtonReleaseMask | ButtonPressMask,
2019 wCursor[WCUR_VERTICALRESIZE], CurrentTime);
2020 else if (res & (LEFT | RIGHT))
2021 XChangeActivePointerGrab(dpy, ButtonMotionMask
2022 | ButtonReleaseMask | ButtonPressMask,
2023 wCursor[WCUR_HORIZONRESIZE], CurrentTime);
2025 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
2027 XGrabServer(dpy);
2029 /* Draw the resize frame for the first time. */
2030 mapGeometryDisplay(wwin, fx, fy, fw, fh);
2032 drawTransparentFrame(wwin, fx, fy, fw, fh);
2034 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2036 started = 1;
2038 if (started) {
2039 if (wPreferences.size_display == WDIS_FRAME_CENTER) {
2040 drawTransparentFrame(wwin, orig_fx, orig_fy, orig_fw, orig_fh);
2041 moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
2042 drawTransparentFrame(wwin, fx, fy, fw, fh);
2043 } else {
2044 drawTransparentFrame(wwin, orig_fx, orig_fy, orig_fw, orig_fh);
2045 drawTransparentFrame(wwin, fx, fy, fw, fh);
2047 if (fh != orig_fh || fw != orig_fw) {
2048 if (wPreferences.size_display == WDIS_NEW) {
2049 showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw,
2050 orig_fy + orig_fh, res);
2052 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2055 break;
2057 case ButtonPress:
2058 break;
2060 case ButtonRelease:
2061 if (event.xbutton.button != ev->xbutton.button)
2062 break;
2064 if (started) {
2065 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
2067 drawTransparentFrame(wwin, fx, fy, fw, fh);
2069 XUngrabKeyboard(dpy, CurrentTime);
2070 WMUnmapWidget(scr->gview);
2071 XUngrabServer(dpy);
2073 if (wwin->client.width != fw)
2074 wwin->flags.user_changed_width = 1;
2076 if (wwin->client.height != fh - vert_border)
2077 wwin->flags.user_changed_height = 1;
2079 wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
2081 #ifdef DEBUG
2082 puts("End resize window");
2083 #endif
2084 return;
2086 default:
2087 WMHandleEvent(&event);
2091 if (wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 && head != wGetHeadForWindow(wwin)) {
2092 wArrangeIcons(scr, True);
2094 #if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP)
2095 wWorkspaceResizeViewport(scr, scr->current_workspace);
2096 #endif
2099 #undef LEFT
2100 #undef RIGHT
2101 #undef HORIZONTAL
2102 #undef UP
2103 #undef DOWN
2104 #undef VERTICAL
2105 #undef HCONSTRAIN
2106 #undef RESIZEBAR
2108 void wUnselectWindows(WScreen * scr)
2110 WWindow *wwin;
2112 if (!scr->selected_windows)
2113 return;
2115 while (WMGetArrayItemCount(scr->selected_windows)) {
2116 wwin = WMGetFromArray(scr->selected_windows, 0);
2117 if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
2118 wIconSelect(wwin->icon);
2120 wSelectWindow(wwin, False);
2122 WMFreeArray(scr->selected_windows);
2123 scr->selected_windows = NULL;
2126 #ifndef LITE
2127 static void selectWindowsInside(WScreen * scr, int x1, int y1, int x2, int y2)
2129 WWindow *tmpw;
2131 /* select the windows and put them in the selected window list */
2132 tmpw = scr->focused_window;
2133 while (tmpw != NULL) {
2134 if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
2135 if ((tmpw->frame->workspace == scr->current_workspace || IS_OMNIPRESENT(tmpw))
2136 && (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1)
2137 && (tmpw->frame->core->width + tmpw->frame_x <= x2)
2138 && (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
2139 wSelectWindow(tmpw, True);
2142 tmpw = tmpw->prev;
2146 void wSelectWindows(WScreen * scr, XEvent * ev)
2148 XEvent event;
2149 Window root = scr->root_win;
2150 GC gc = scr->frame_gc;
2151 int xp = ev->xbutton.x_root;
2152 int yp = ev->xbutton.y_root;
2153 int w = 0, h = 0;
2154 int x = xp, y = yp;
2156 #ifdef DEBUG
2157 puts("Selecting windows");
2158 #endif
2159 if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
2160 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
2161 GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
2162 return;
2164 XGrabServer(dpy);
2166 wUnselectWindows(scr);
2168 XDrawRectangle(dpy, root, gc, xp, yp, w, h);
2169 while (1) {
2170 WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask | ButtonPressMask, &event);
2172 switch (event.type) {
2173 case MotionNotify:
2174 XDrawRectangle(dpy, root, gc, x, y, w, h);
2175 x = event.xmotion.x_root;
2176 if (x < xp) {
2177 w = xp - x;
2178 } else {
2179 w = x - xp;
2180 x = xp;
2182 y = event.xmotion.y_root;
2183 if (y < yp) {
2184 h = yp - y;
2185 } else {
2186 h = y - yp;
2187 y = yp;
2189 XDrawRectangle(dpy, root, gc, x, y, w, h);
2190 break;
2192 case ButtonPress:
2193 break;
2195 case ButtonRelease:
2196 if (event.xbutton.button != ev->xbutton.button)
2197 break;
2199 XDrawRectangle(dpy, root, gc, x, y, w, h);
2200 XUngrabServer(dpy);
2201 XUngrabPointer(dpy, CurrentTime);
2202 selectWindowsInside(scr, x, y, x + w, y + h);
2204 #ifdef DEBUG
2205 puts("End window selection");
2206 #endif
2207 return;
2209 default:
2210 WMHandleEvent(&event);
2211 break;
2215 #endif /* !LITE */
2217 void InteractivePlaceWindow(WWindow * wwin, int *x_ret, int *y_ret, unsigned width, unsigned height)
2219 WScreen *scr = wwin->screen_ptr;
2220 Window root = scr->root_win;
2221 int x, y, h = 0;
2222 XEvent event;
2223 KeyCode shiftl, shiftr;
2224 Window junkw;
2225 int junk;
2227 if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
2228 GrabModeAsync, GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
2229 *x_ret = 0;
2230 *y_ret = 0;
2231 return;
2233 if (HAS_TITLEBAR(wwin)) {
2234 h = WMFontHeight(scr->title_font) + (wPreferences.window_title_clearance +
2235 TITLEBAR_EXTEND_SPACE) * 2;
2236 height += h;
2238 if (HAS_RESIZEBAR(wwin)) {
2239 height += RESIZEBAR_HEIGHT;
2241 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
2242 XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk, (unsigned *)&junk);
2243 mapPositionDisplay(wwin, x - width / 2, y - h / 2, width, height);
2245 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2247 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
2248 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
2249 while (1) {
2250 WMMaskEvent(dpy, PointerMotionMask | ButtonPressMask | ExposureMask | KeyPressMask, &event);
2252 if (!checkMouseSamplingRate(&event))
2253 continue;
2255 switch (event.type) {
2256 case KeyPress:
2257 if ((event.xkey.keycode == shiftl)
2258 || (event.xkey.keycode == shiftr)) {
2259 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2260 cyclePositionDisplay(wwin, x - width / 2, y - h / 2, width, height);
2261 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2263 break;
2265 case MotionNotify:
2266 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2268 x = event.xmotion.x_root;
2269 y = event.xmotion.y_root;
2271 if (wPreferences.move_display == WDIS_FRAME_CENTER)
2272 moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
2274 showPosition(wwin, x - width / 2, y - h / 2);
2276 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2278 break;
2280 case ButtonPress:
2281 drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
2282 XSync(dpy, 0);
2283 *x_ret = x - width / 2;
2284 *y_ret = y - h / 2;
2285 XUngrabPointer(dpy, CurrentTime);
2286 XUngrabKeyboard(dpy, CurrentTime);
2287 /* get rid of the geometry window */
2288 WMUnmapWidget(scr->gview);
2289 return;
2291 default:
2292 WMHandleEvent(&event);
2293 break;