2 * Window Maker window manager
4 * Copyright (c) 1997, 1998, 1999 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,
25 #include <X11/Xutil.h>
26 #include <X11/keysym.h>
32 #include "WindowMaker.h"
41 #include "workspace.h"
48 /* How many different types of geometry/position
49 display thingies are there? */
50 #define NUM_DISPLAYS 4
54 #define HORIZONTAL (LEFT|RIGHT)
57 #define VERTICAL (UP|DOWN)
59 /****** Global Variables ******/
60 extern Time LastTimestamp
;
62 extern Cursor wCursor
[WCUR_LAST
];
64 extern WPreferences wPreferences
;
66 extern Atom _XA_WM_PROTOCOLS
;
74 wGetGeometryWindowSize(WScreen
*scr
, unsigned int *width
,
77 *width
= WMWidthOfString(scr
->info_text_font
, "-8888 x -8888", 13);
79 *height
= (6 * WMFontHeight(scr
->info_text_font
)) / 4 - 1;
85 *----------------------------------------------------------------------
86 * checkMouseSamplingRate-
87 * For lowering the mouse motion sampling rate for machines where
88 * it's too high (SGIs). If it returns False then the event should be
90 *----------------------------------------------------------------------
93 checkMouseSamplingRate(XEvent
*ev
)
95 static Time previousMotion
= 0;
97 if (ev
->type
== MotionNotify
) {
98 if (ev
->xmotion
.time
- previousMotion
< DELAY_BETWEEN_MOUSE_SAMPLING
) {
101 previousMotion
= ev
->xmotion
.time
;
110 *----------------------------------------------------------------------
111 * moveGeometryDisplayCentered
113 * routine that moves the geometry/position window on scr so it is
114 * centered over the given coordinates (x,y). Also the window position
115 * is clamped so it stays on the screen at all times.
116 *----------------------------------------------------------------------
119 moveGeometryDisplayCentered(WScreen
*scr
, int x
, int y
)
121 x
-= scr
->geometry_display_width
/ 2;
122 y
-= scr
->geometry_display_height
/ 2;
126 else if (x
> (scr
->scr_width
- scr
->geometry_display_width
- 3))
127 x
= scr
->scr_width
- scr
->geometry_display_width
- 3;
131 else if (y
> (scr
->scr_height
- scr
->geometry_display_height
- 3))
132 y
= scr
->scr_height
- scr
->geometry_display_height
- 3;
134 XMoveWindow(dpy
, scr
->geometry_display
, x
, y
);
139 showPosition(WWindow
*wwin
, int x
, int y
)
141 WScreen
*scr
= wwin
->screen_ptr
;
142 GC gc
= scr
->info_text_gc
;
146 if (wPreferences
.move_display
== WDIS_NEW
) {
148 int width
= wwin
->frame
->core
->width
;
149 int height
= wwin
->frame
->core
->height
;
151 GC lgc
= scr
->line_gc
;
152 XSetForeground(dpy
, lgc
, scr
->line_pixel
);
153 sprintf(num
, "%i", x
);
155 XDrawLine(dpy
, scr
->root_win
, lgc
, 0, y
-1, scr
->scr_width
, y
-1);
156 XDrawLine(dpy
, scr
->root_win
, lgc
, 0, y
+height
+2, scr
->scr_width
,
158 XDrawLine(dpy
, scr
->root_win
, lgc
, x
-1, 0, x
-1, scr
->scr_height
);
159 XDrawLine(dpy
, scr
->root_win
, lgc
, x
+width
+2, 0, x
+width
+2,
163 XClearArea(dpy
, scr
->geometry_display
, 1, 1,
164 scr
->geometry_display_width
-2, scr
->geometry_display_height
-2,
166 sprintf(num
, "%+i %-+i", x
, y
);
167 fw
= WMWidthOfString(scr
->info_text_font
, num
, strlen(num
));
169 XSetForeground(dpy
, gc
, scr
->black_pixel
);
171 fh
= WMFontHeight(scr
->info_text_font
);
172 WMDrawString(scr
->wmscreen
, scr
->geometry_display
, gc
,
174 (scr
->geometry_display_width
- 2 - fw
) / 2,
175 (scr
->geometry_display_height
-fh
)/2, num
, strlen(num
));
176 wDrawBevel(scr
->geometry_display
, scr
->geometry_display_width
+1,
177 scr
->geometry_display_height
+1,
178 scr
->widget_texture
, WREL_RAISED
);
184 cyclePositionDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
)
186 WScreen
*scr
= wwin
->screen_ptr
;
188 wPreferences
.move_display
++;
189 wPreferences
.move_display
%= NUM_DISPLAYS
;
191 if (wPreferences
.move_display
== WDIS_NEW
) {
192 XUnmapWindow(dpy
, scr
->geometry_display
);
194 if (wPreferences
.move_display
== WDIS_CENTER
) {
195 moveGeometryDisplayCentered(scr
,
196 scr
->scr_width
/2, scr
->scr_height
/2);
197 } else if (wPreferences
.move_display
== WDIS_TOPLEFT
) {
198 moveGeometryDisplayCentered(scr
, 1, 1);
199 } else if (wPreferences
.move_display
== WDIS_FRAME_CENTER
) {
200 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
202 XMapRaised(dpy
, scr
->geometry_display
);
208 mapPositionDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
)
210 WScreen
*scr
= wwin
->screen_ptr
;
212 if (wPreferences
.move_display
== WDIS_NEW
) {
214 } else if (wPreferences
.move_display
== WDIS_CENTER
) {
215 moveGeometryDisplayCentered(scr
, scr
->scr_width
/ 2,
216 scr
->scr_height
/ 2);
217 } else if (wPreferences
.move_display
== WDIS_TOPLEFT
) {
218 moveGeometryDisplayCentered(scr
, 1, 1);
219 } else if (wPreferences
.move_display
== WDIS_FRAME_CENTER
) {
220 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
222 XMapRaised(dpy
, scr
->geometry_display
);
223 showPosition(wwin
, x
, y
);
226 #define unmapPositionDisplay(w) \
227 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
231 showGeometry(WWindow
*wwin
, int x1
, int y1
, int x2
, int y2
, int direction
)
233 WScreen
*scr
= wwin
->screen_ptr
;
234 Window root
= scr
->root_win
;
235 GC gc
= scr
->line_gc
;
236 int ty
, by
, my
, x
, y
, mx
, s
;
241 ty
= y1
+ wwin
->frame
->top_width
;
242 by
= y2
- wwin
->frame
->bottom_width
;
243 fw
= WMWidthOfString(scr
->info_text_font
, "8888", 4);
244 fh
= WMFontHeight(scr
->info_text_font
);
246 if (wPreferences
.size_display
== WDIS_NEW
) {
247 XSetForeground(dpy
, gc
, scr
->line_pixel
);
249 /* vertical geometry */
250 if (((direction
& LEFT
) && (x2
< scr
->scr_width
- fw
)) || (x1
< fw
)) {
261 segment
[0].x1
= x
- (s
+ 6); segment
[0].y1
= ty
;
262 segment
[0].x2
= x
- (s
- 10); segment
[0].y2
= ty
;
265 segment
[1].x1
= x
- (s
- 2); segment
[1].y1
= ty
+ 1;
266 segment
[1].x2
= x
- (s
- 5); segment
[1].y2
= ty
+ 7;
268 segment
[2].x1
= x
- (s
- 2); segment
[2].y1
= ty
+ 1;
269 segment
[2].x2
= x
- (s
+ 1); segment
[2].y2
= ty
+ 7;
272 segment
[3].x1
= x
- (s
- 2); segment
[3].y1
= ty
+ 1;
273 segment
[3].x2
= x
- (s
- 2); segment
[3].y2
= my
- fh
/2 - 1;
275 XDrawSegments(dpy
, root
, gc
, segment
, 4);
283 segment
[1].y1
= by
- 1;
284 segment
[1].y2
= by
- 7;
286 segment
[2].y1
= by
- 1;
287 segment
[2].y2
= by
- 7;
290 segment
[3].y1
= my
+ fh
/2 + 2;
291 segment
[3].y2
= by
- 1;
293 XDrawSegments(dpy
, root
, gc
, segment
, 4);
295 sprintf(num
, "%i", (by
- ty
- wwin
->normal_hints
->base_height
) /
296 wwin
->normal_hints
->height_inc
);
297 fw
= WMWidthOfString(scr
->info_text_font
, num
, strlen(num
));
299 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
301 /* Display the height. */
302 WMDrawString(scr
->wmscreen
, root
, gc
, scr
->info_text_font
,
303 x
- s
+ 3 - fw
/2, my
- fh
/2 + 1, num
, strlen(num
));
304 XSetForeground(dpy
, gc
, scr
->line_pixel
);
305 /* horizontal geometry */
313 mx
= x1
+ (x2
- x1
)/2;
314 sprintf(num
, "%i", (x2
- x1
- wwin
->normal_hints
->base_width
) /
315 wwin
->normal_hints
->width_inc
);
316 fw
= WMWidthOfString(scr
->info_text_font
, num
, strlen(num
));
320 segment
[0].x1
= x1
; segment
[0].y1
= y
- (s
+ 6);
321 segment
[0].x2
= x1
; segment
[0].y2
= y
- (s
- 10);
324 segment
[1].x1
= x1
+ 7; segment
[1].y1
= y
- (s
+ 1);
325 segment
[1].x2
= x1
+ 1; segment
[1].y2
= y
- (s
- 2);
327 segment
[2].x1
= x1
+ 1; segment
[2].y1
= y
- (s
- 2);
328 segment
[2].x2
= x1
+ 7; segment
[2].y2
= y
- (s
- 5);
331 segment
[3].x1
= x1
+ 1; segment
[3].y1
= y
- (s
- 2);
332 segment
[3].x2
= mx
- fw
/2 - 2; segment
[3].y2
= y
- (s
- 2);
334 XDrawSegments(dpy
, root
, gc
, segment
, 4);
338 segment
[0].x1
= x2
+ 1;
339 segment
[0].x2
= x2
+ 1;
342 segment
[1].x1
= x2
- 6;
346 segment
[2].x2
= x2
- 6;
349 segment
[3].x1
= mx
+ fw
/2 + 2;
352 XDrawSegments(dpy
, root
, gc
, segment
, 4);
354 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
356 /* Display the width. */
357 WMDrawString(scr
->wmscreen
, root
, gc
, scr
->info_text_font
,
358 mx
- fw
/2 + 1, y
- s
- fh
/2 + 1, num
, strlen(num
));
360 XClearArea(dpy
, scr
->geometry_display
, 1, 1,
361 scr
->geometry_display_width
-2, scr
->geometry_display_height
-2,
363 sprintf(num
, "%i x %-i", (x2
- x1
- wwin
->normal_hints
->base_width
)
364 / wwin
->normal_hints
->width_inc
,
365 (by
- ty
- wwin
->normal_hints
->base_height
)
366 / wwin
->normal_hints
->height_inc
);
367 fw
= WMWidthOfString(scr
->info_text_font
, num
, strlen(num
));
369 XSetForeground(dpy
, scr
->info_text_gc
, scr
->black_pixel
);
371 /* Display the height. */
372 WMDrawString(scr
->wmscreen
, scr
->geometry_display
, scr
->info_text_gc
,
374 (scr
->geometry_display_width
-fw
)/2,
375 (scr
->geometry_display_height
-fh
)/2, num
, strlen(num
));
376 wDrawBevel(scr
->geometry_display
, scr
->geometry_display_width
+1,
377 scr
->geometry_display_height
+1,
378 scr
->widget_texture
, WREL_RAISED
);
384 cycleGeometryDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
, int dir
)
386 WScreen
*scr
= wwin
->screen_ptr
;
388 wPreferences
.size_display
++;
389 wPreferences
.size_display
%= NUM_DISPLAYS
;
391 if (wPreferences
.size_display
== WDIS_NEW
) {
392 XUnmapWindow(dpy
, scr
->geometry_display
);
394 if (wPreferences
.size_display
== WDIS_CENTER
) {
395 moveGeometryDisplayCentered(scr
,
396 scr
->scr_width
/ 2, scr
->scr_height
/ 2);
397 } else if (wPreferences
.size_display
== WDIS_TOPLEFT
) {
398 moveGeometryDisplayCentered(scr
, 1, 1);
399 } else if (wPreferences
.size_display
== WDIS_FRAME_CENTER
) {
400 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
402 XMapRaised(dpy
, scr
->geometry_display
);
403 showGeometry(wwin
, x
, y
, x
+ w
, y
+ h
, dir
);
409 mapGeometryDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
)
411 WScreen
*scr
= wwin
->screen_ptr
;
413 if (wPreferences
.size_display
== WDIS_NEW
)
416 if (wPreferences
.size_display
== WDIS_CENTER
) {
417 moveGeometryDisplayCentered(scr
, scr
->scr_width
/ 2,
418 scr
->scr_height
/ 2);
419 } else if (wPreferences
.size_display
== WDIS_TOPLEFT
) {
420 moveGeometryDisplayCentered(scr
, 1, 1);
421 } else if (wPreferences
.size_display
== WDIS_FRAME_CENTER
) {
422 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
424 XMapRaised(dpy
, scr
->geometry_display
);
425 showGeometry(wwin
, x
, y
, x
+ w
, y
+ h
, 0);
428 #define unmapGeometryDisplay(w) \
429 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
433 doWindowMove(WWindow
*wwin
, WMBag
*bag
, int dx
, int dy
)
437 int scr_width
= wwin
->screen_ptr
->scr_width
;
438 int scr_height
= wwin
->screen_ptr
->scr_height
;
440 if (!bag
|| !WMGetBagItemCount(bag
)) {
441 wWindowMove(wwin
, wwin
->frame_x
+ dx
, wwin
->frame_y
+ dy
);
444 for (i
= 0; i
< WMGetBagItemCount(bag
); i
++) {
445 tmpw
= WMGetFromBag(bag
, i
);
446 x
= tmpw
->frame_x
+ dx
;
447 y
= tmpw
->frame_y
+ dy
;
449 /* don't let windows become unreachable */
451 if (x
+ (int)tmpw
->frame
->core
->width
< 20)
452 x
= 20 - (int)tmpw
->frame
->core
->width
;
453 else if (x
+ 20 > scr_width
)
456 if (y
+ (int)tmpw
->frame
->core
->height
< 20)
457 y
= 20 - (int)tmpw
->frame
->core
->height
;
458 else if (y
+ 20 > scr_height
)
461 wWindowMove(tmpw
, x
, y
);
468 drawTransparentFrame(WWindow
*wwin
, int x
, int y
, int width
, int height
)
470 Window root
= wwin
->screen_ptr
->root_win
;
471 GC gc
= wwin
->screen_ptr
->frame_gc
;
475 if (!WFLAGP(wwin
, no_titlebar
) && !wwin
->flags
.shaded
) {
476 h
= WMFontHeight(wwin
->screen_ptr
->title_font
) + TITLEBAR_EXTRA_HEIGHT
;
478 if (!WFLAGP(wwin
, no_resizebar
) && !wwin
->flags
.shaded
) {
479 /* Can't use wwin-frame->bottom_width because, in some cases
480 (e.g. interactive placement), frame does not point to anything. */
481 bottom
= RESIZEBAR_HEIGHT
- 1;
483 XDrawRectangle(dpy
, root
, gc
, x
, y
, width
+ 1, height
+ 1);
486 XDrawLine(dpy
, root
, gc
, x
+ 1, y
+ h
, x
+ width
+ 1, y
+ h
);
489 XDrawLine(dpy
, root
, gc
, x
+ 1,
492 y
+ height
- bottom
);
498 drawFrames(WWindow
*wwin
, WMBag
*bag
, int dx
, int dy
)
501 int scr_width
= wwin
->screen_ptr
->scr_width
;
502 int scr_height
= wwin
->screen_ptr
->scr_height
;
507 x
= wwin
->frame_x
+ dx
;
508 y
= wwin
->frame_y
+ dy
;
510 drawTransparentFrame(wwin
, x
, y
,
511 wwin
->frame
->core
->width
,
512 wwin
->frame
->core
->height
);
516 for (i
= 0; i
< WMGetBagItemCount(bag
); i
++) {
517 tmpw
= WMGetFromBag(bag
, i
);
518 x
= tmpw
->frame_x
+ dx
;
519 y
= tmpw
->frame_y
+ dy
;
521 /* don't let windows become unreachable */
523 if (x
+ (int)tmpw
->frame
->core
->width
< 20)
524 x
= 20 - (int)tmpw
->frame
->core
->width
;
525 else if (x
+ 20 > scr_width
)
528 if (y
+ (int)tmpw
->frame
->core
->height
< 20)
529 y
= 20 - (int)tmpw
->frame
->core
->height
;
530 else if (y
+ 20 > scr_height
)
533 drawTransparentFrame(tmpw
, x
, y
, tmpw
->frame
->core
->width
,
534 tmpw
->frame
->core
->height
);
547 while (XCheckMaskEvent(dpy
, ButtonMotionMask
, &ev
)) ;
552 crossWorkspace(WScreen
*scr
, WWindow
*wwin
, int opaque_move
,
553 int new_workspace
, int rewind
)
555 /* do not let window be unmapped */
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;
566 XWarpPointer(dpy
, None
, None
, 0, 0, 0, 0, scr
->scr_width
- 20, 0);
568 XWarpPointer(dpy
, None
, None
, 0, 0, 0, 0, -(scr
->scr_width
- 20), 0);
573 XGrabPointer(dpy
, scr
->root_win
, True
, PointerMotionMask
574 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
575 GrabModeAsync
, None
, wCursor
[WCUR_MOVE
], CurrentTime
);
583 /* arrays of WWindows sorted by the respective border position */
584 WWindow
**topList
; /* top border */
585 WWindow
**leftList
; /* left border */
586 WWindow
**rightList
; /* right border */
587 WWindow
**bottomList
; /* bottom border */
590 /* index of window in the above lists indicating the relative position
591 * of the window with the others */
597 int rubCount
; /* for workspace switching */
599 int winWidth
, winHeight
; /* width/height of the window */
600 int realX
, realY
; /* actual position of the window */
601 int calcX
, calcY
; /* calculated position of window */
602 int omouseX
, omouseY
; /* old mouse position */
603 int mouseX
, mouseY
; /* last known position of the pointer */
606 #define WTOP(w) (w)->frame_y
607 #define WLEFT(w) (w)->frame_x
608 #define WRIGHT(w) ((w)->frame_x + (int)(w)->frame->core->width + FRAME_BORDER_WIDTH)
609 #define WBOTTOM(w) ((w)->frame_y + (int)(w)->frame->core->height + FRAME_BORDER_WIDTH)
612 compareWTop(const void *a
, const void *b
)
614 WWindow
*wwin1
= *(WWindow
**)a
;
615 WWindow
*wwin2
= *(WWindow
**)b
;
617 if (WTOP(wwin1
) > WTOP(wwin2
))
619 else if (WTOP(wwin1
) < WTOP(wwin2
))
627 compareWLeft(const void *a
, const void *b
)
629 WWindow
*wwin1
= *(WWindow
**)a
;
630 WWindow
*wwin2
= *(WWindow
**)b
;
632 if (WLEFT(wwin1
) > WLEFT(wwin2
))
634 else if (WLEFT(wwin1
) < WLEFT(wwin2
))
642 compareWRight(const void *a
, const void *b
)
644 WWindow
*wwin1
= *(WWindow
**)a
;
645 WWindow
*wwin2
= *(WWindow
**)b
;
647 if (WRIGHT(wwin1
) < WRIGHT(wwin2
))
649 else if (WRIGHT(wwin1
) > WRIGHT(wwin2
))
658 compareWBottom(const void *a
, const void *b
)
660 WWindow
*wwin1
= *(WWindow
**)a
;
661 WWindow
*wwin2
= *(WWindow
**)b
;
663 if (WBOTTOM(wwin1
) < WBOTTOM(wwin2
))
665 else if (WBOTTOM(wwin1
) > WBOTTOM(wwin2
))
673 updateResistance(WWindow
*wwin
, MoveData
*data
, int newX
, int newY
)
676 int newX2
= newX
+ data
->winWidth
;
677 int newY2
= newY
+ data
->winHeight
;
680 if (newX
< data
->realX
) {
681 if (data
->rightIndex
> 0
682 && newX
< WRIGHT(data
->rightList
[data
->rightIndex
-1])) {
684 } else if (data
->leftIndex
<= data
->count
-1
685 && newX2
<= WLEFT(data
->leftList
[data
->leftIndex
])) {
688 } else if (newX
> data
->realX
) {
689 if (data
->leftIndex
> 0
690 && newX2
> WLEFT(data
->leftList
[data
->leftIndex
-1])) {
692 } else if (data
->rightIndex
<= data
->count
-1
693 && newX
>= WRIGHT(data
->rightList
[data
->rightIndex
])) {
699 if (newY
< data
->realY
) {
700 if (data
->bottomIndex
> 0
701 && newY
< WBOTTOM(data
->bottomList
[data
->bottomIndex
-1])) {
703 } else if (data
->topIndex
<= data
->count
-1
704 && newY2
<= WTOP(data
->topList
[data
->topIndex
])) {
707 } else if (newY
> data
->realY
) {
708 if (data
->topIndex
> 0
709 && newY2
> WTOP(data
->topList
[data
->topIndex
-1])) {
711 } else if (data
->bottomIndex
<= data
->count
-1
712 && newY
>= WBOTTOM(data
->bottomList
[data
->bottomIndex
])) {
721 /* TODO: optimize this */
722 if (data
->realY
< WBOTTOM(data
->bottomList
[0])) {
723 data
->bottomIndex
= 0;
725 if (data
->realX
< WRIGHT(data
->rightList
[0])) {
726 data
->rightIndex
= 0;
728 if ((data
->realX
+ data
->winWidth
) > WLEFT(data
->leftList
[0])) {
731 if ((data
->realY
+ data
->winHeight
) > WTOP(data
->topList
[0])) {
734 for (i
= 0; i
< data
->count
; i
++) {
735 if (data
->realY
> WBOTTOM(data
->bottomList
[i
])) {
736 data
->bottomIndex
= i
+ 1;
738 if (data
->realX
> WRIGHT(data
->rightList
[i
])) {
739 data
->rightIndex
= i
+ 1;
741 if ((data
->realX
+ data
->winWidth
) < WLEFT(data
->leftList
[i
])) {
742 data
->leftIndex
= i
+ 1;
744 if ((data
->realY
+ data
->winHeight
) < WTOP(data
->topList
[i
])) {
745 data
->topIndex
= i
+ 1;
752 freeMoveData(MoveData
*data
)
757 free(data
->leftList
);
759 free(data
->rightList
);
760 if (data
->bottomList
)
761 free(data
->bottomList
);
766 updateMoveData(WWindow
*wwin
, MoveData
*data
)
768 WScreen
*scr
= wwin
->screen_ptr
;
773 tmp
= scr
->focused_window
;
775 if (tmp
!= wwin
&& scr
->current_workspace
== tmp
->frame
->workspace
776 && !tmp
->flags
.miniaturized
777 && !tmp
->flags
.hidden
778 && !tmp
->flags
.obscured
779 && !WFLAGP(tmp
, sunken
)) {
780 data
->topList
[data
->count
] = tmp
;
781 data
->leftList
[data
->count
] = tmp
;
782 data
->rightList
[data
->count
] = tmp
;
783 data
->bottomList
[data
->count
] = tmp
;
789 if (data
->count
== 0) {
792 data
->rightIndex
= 0;
793 data
->bottomIndex
= 0;
798 * order from closest to the border of the screen to farthest
800 qsort(data
->topList
, data
->count
, sizeof(WWindow
**), compareWTop
);
801 qsort(data
->leftList
, data
->count
, sizeof(WWindow
**), compareWLeft
);
802 qsort(data
->rightList
, data
->count
, sizeof(WWindow
**), compareWRight
);
803 qsort(data
->bottomList
, data
->count
, sizeof(WWindow
**), compareWBottom
);
805 /* figure the position of the window relative to the others */
808 data
->leftIndex
= -1;
809 data
->rightIndex
= -1;
810 data
->bottomIndex
= -1;
812 if (WTOP(wwin
) < WBOTTOM(data
->bottomList
[0])) {
813 data
->bottomIndex
= 0;
815 if (WLEFT(wwin
) < WRIGHT(data
->rightList
[0])) {
816 data
->rightIndex
= 0;
818 if (WRIGHT(wwin
) > WLEFT(data
->leftList
[0])) {
821 if (WBOTTOM(wwin
) > WTOP(data
->topList
[0])) {
824 for (i
= 0; i
< data
->count
; i
++) {
825 if (WTOP(wwin
) >= WBOTTOM(data
->bottomList
[i
])) {
826 data
->bottomIndex
= i
+ 1;
828 if (WLEFT(wwin
) >= WRIGHT(data
->rightList
[i
])) {
829 data
->rightIndex
= i
+ 1;
831 if (WRIGHT(wwin
) <= WLEFT(data
->leftList
[i
])) {
832 data
->leftIndex
= i
+ 1;
834 if (WBOTTOM(wwin
) <= WTOP(data
->topList
[i
])) {
835 data
->topIndex
= i
+ 1;
842 initMoveData(WWindow
*wwin
, MoveData
*data
)
847 memset(data
, 0, sizeof(MoveData
));
849 for (i
= 0, tmp
= wwin
->screen_ptr
->focused_window
;
851 tmp
= tmp
->prev
, i
++);
854 data
->topList
= wmalloc(sizeof(WWindow
*) * i
);
855 data
->leftList
= wmalloc(sizeof(WWindow
*) * i
);
856 data
->rightList
= wmalloc(sizeof(WWindow
*) * i
);
857 data
->bottomList
= wmalloc(sizeof(WWindow
*) * i
);
859 updateMoveData(wwin
, data
);
862 data
->realX
= wwin
->frame_x
;
863 data
->realY
= wwin
->frame_y
;
864 data
->calcX
= wwin
->frame_x
;
865 data
->calcY
= wwin
->frame_y
;
867 data
->winWidth
= wwin
->frame
->core
->width
+ 2;
868 data
->winHeight
= wwin
->frame
->core
->height
+ 2;
873 checkWorkspaceChange(WWindow
*wwin
, MoveData
*data
, Bool opaqueMove
)
875 WScreen
*scr
= wwin
->screen_ptr
;
876 Bool changed
= False
;
878 if (data
->mouseX
<= 1) {
879 if (scr
->current_workspace
> 0) {
881 crossWorkspace(scr
, wwin
, opaqueMove
, scr
->current_workspace
- 1,
886 } else if (scr
->current_workspace
== 0 && wPreferences
.ws_cycle
) {
888 crossWorkspace(scr
, wwin
, opaqueMove
, scr
->workspace_count
- 1,
893 } else if (data
->mouseX
>= scr
->scr_width
- 2) {
895 if (scr
->current_workspace
== scr
->workspace_count
- 1) {
897 if (wPreferences
.ws_cycle
898 || scr
->workspace_count
== MAX_WORKSPACES
) {
900 crossWorkspace(scr
, wwin
, opaqueMove
, 0, False
);
904 /* if user insists on trying to go to next workspace even when
905 * it's already the last, create a new one */
906 else if (data
->omouseX
== data
->mouseX
907 && wPreferences
.ws_advance
) {
909 /* detect user "rubbing" the window against the edge */
910 if (data
->rubCount
> 0
911 && data
->omouseY
- data
->mouseY
> MOVE_THRESHOLD
) {
913 data
->rubCount
= -(data
->rubCount
+ 1);
915 } else if (data
->rubCount
<= 0
916 && data
->mouseY
- data
->omouseY
> MOVE_THRESHOLD
) {
918 data
->rubCount
= -data
->rubCount
+ 1;
921 /* create a new workspace */
922 if (abs(data
->rubCount
) > 2) {
923 /* go to next workspace */
926 crossWorkspace(scr
, wwin
, opaqueMove
,
927 scr
->current_workspace
+1, False
);
931 } else if (scr
->current_workspace
< scr
->workspace_count
) {
933 /* go to next workspace */
934 crossWorkspace(scr
, wwin
, opaqueMove
,
935 scr
->current_workspace
+1, False
);
948 updateWindowPosition(WWindow
*wwin
, MoveData
*data
, Bool doResistance
,
949 Bool opaqueMove
, int newMouseX
, int newMouseY
)
951 WScreen
*scr
= wwin
->screen_ptr
;
952 int dx
, dy
; /* how much mouse moved */
953 int winL
, winR
, winT
, winB
; /* requested new window position */
954 int newX
, newY
; /* actual new window position */
955 Bool hresist
, vresist
;
964 /* check the direction of the movement */
965 dx
= newMouseX
- data
->mouseX
;
966 dy
= newMouseY
- data
->mouseY
;
968 data
->omouseX
= data
->mouseX
;
969 data
->omouseY
= data
->mouseY
;
970 data
->mouseX
= newMouseX
;
971 data
->mouseY
= newMouseY
;
973 winL
= data
->calcX
+ dx
;
974 winR
= data
->calcX
+ data
->winWidth
+ dx
;
975 winT
= data
->calcY
+ dy
;
976 winB
= data
->calcY
+ data
->winHeight
+ dy
;
988 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
989 attract
= wPreferences
.attract
;
990 /* horizontal movement: check horizontal edge resistances */
993 /* window is the leftmost window: check against screen edge */
994 l_edge
= scr
->totalUsableArea
.x1
;
995 r_edge
= scr
->totalUsableArea
.x2
+ resist
;
996 edge_l
= scr
->totalUsableArea
.x1
- resist
;
997 edge_r
= scr
->totalUsableArea
.x2
;
1000 if ((data
->rightIndex
>= 0) && (data
->rightIndex
<= data
->count
)) {
1003 for (i
= data
->rightIndex
- 1; i
>= 0; i
--) {
1004 looprw
= data
->rightList
[i
];
1005 if (!(data
->realY
> WBOTTOM(looprw
)
1006 || (data
->realY
+ data
->winHeight
) < WTOP(looprw
))) {
1008 || ((data
->realX
< (WRIGHT(looprw
) + 2)) && dx
< 0)) {
1009 l_edge
= WRIGHT(looprw
) + 1;
1010 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
1017 for (i
= data
->rightIndex
; i
< data
->count
; i
++) {
1018 looprw
= data
->rightList
[i
];
1019 if(!(data
->realY
> WBOTTOM(looprw
)
1020 || (data
->realY
+ data
->winHeight
) < WTOP(looprw
))) {
1021 r_edge
= WRIGHT(looprw
) + 1;
1022 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
1029 if ((data
->leftIndex
>= 0) && (data
->leftIndex
<= data
->count
)) {
1032 for (i
= data
->leftIndex
- 1; i
>= 0; i
--) {
1033 looprw
= data
->leftList
[i
];
1034 if (!(data
->realY
> WBOTTOM(looprw
)
1035 || (data
->realY
+ data
->winHeight
) < WTOP(looprw
))) {
1037 || (((data
->realX
+ data
->winWidth
) > (WLEFT(looprw
) - 1)) && dx
> 0)) {
1038 edge_r
= WLEFT(looprw
);
1039 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
1046 for (i
= data
->leftIndex
; i
< data
->count
; i
++) {
1047 looprw
= data
->leftList
[i
];
1048 if(!(data
->realY
> WBOTTOM(looprw
)
1049 || (data
->realY
+ data
->winHeight
) < WTOP(looprw
))) {
1050 edge_l
= WLEFT(looprw
);
1051 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
1058 printf("%d %d\n",winL,winR);
1059 printf("l_ %d r_ %d _l %d _r %d\n",l_edge,r_edge,edge_l,edge_r);
1062 if ((winL
- l_edge
) < (r_edge
- winL
)) {
1064 if ((attract
&& winL
<= l_edge
+ resist
&& winL
>= l_edge
- resist
)
1065 || (dx
< 0 && winL
<= l_edge
&& winL
>= l_edge
- resist
)) {
1071 if (resist
> 0 && attract
&& winL
>= r_edge
- resist
&& winL
<= r_edge
+ resist
) {
1077 if ((winR
- edge_l
) < (edge_r
- winR
)) {
1078 if (resist
> 0 && attract
&& winR
<= edge_l
+ resist
&& winR
>= edge_l
- resist
) {
1079 newX
= edge_l
- data
->winWidth
;
1084 if ((attract
&& winR
>= edge_r
- resist
&& winR
<= edge_r
+ resist
)
1085 || (dx
> 0 && winR
>= edge_r
&& winR
<= edge_r
+ resist
)) {
1086 newX
= edge_r
- data
->winWidth
;
1093 t_edge
= scr
->totalUsableArea
.y1
;
1094 b_edge
= scr
->totalUsableArea
.y2
+ resist
;
1095 edge_t
= scr
->totalUsableArea
.y1
- resist
;
1096 edge_b
= scr
->totalUsableArea
.y2
;
1098 if ((data
->bottomIndex
>= 0) && (data
->bottomIndex
<= data
->count
)) {
1101 for (i
= data
->bottomIndex
- 1; i
>= 0; i
--) {
1102 looprw
= data
->bottomList
[i
];
1103 if (!(data
->realX
> WRIGHT(looprw
)
1104 || (data
->realX
+ data
->winWidth
) < WLEFT(looprw
))) {
1106 || ((data
->realY
< (WBOTTOM(looprw
) + 2)) && dy
< 0)) {
1107 t_edge
= WBOTTOM(looprw
) + 1;
1108 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
1115 for (i
= data
->bottomIndex
; i
< data
->count
; i
++) {
1116 looprw
= data
->bottomList
[i
];
1117 if(!(data
->realX
> WRIGHT(looprw
)
1118 || (data
->realX
+ data
->winWidth
) < WLEFT(looprw
))) {
1119 b_edge
= WBOTTOM(looprw
) + 1;
1120 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
1127 if ((data
->topIndex
>= 0) && (data
->topIndex
<= data
->count
)) {
1130 for (i
= data
->topIndex
- 1; i
>= 0; i
--) {
1131 looprw
= data
->topList
[i
];
1132 if (!(data
->realX
> WRIGHT(looprw
)
1133 || (data
->realX
+ data
->winWidth
) < WLEFT(looprw
))) {
1135 || (((data
->realY
+ data
->winHeight
) > (WTOP(looprw
) - 1)) && dy
> 0)) {
1136 edge_b
= WTOP(looprw
);
1137 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
1144 for (i
= data
->topIndex
; i
< data
->count
; i
++) {
1145 looprw
= data
->topList
[i
];
1146 if(!(data
->realX
> WRIGHT(looprw
)
1147 || (data
->realX
+ data
->winWidth
) < WLEFT(looprw
))) {
1148 edge_t
= WTOP(looprw
);
1149 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
1155 if ((winT
- t_edge
) < (b_edge
- winT
)) {
1157 if ((attract
&& winT
<= t_edge
+ resist
&& winT
>= t_edge
- resist
)
1158 || (dy
< 0 && winT
<= t_edge
&& winT
>= t_edge
- resist
)) {
1165 if (resist
> 0 && attract
&& winT
>= b_edge
- resist
&& winT
<= b_edge
+ resist
) {
1171 if ((winB
- edge_t
) < (edge_b
- winB
)) {
1172 if (resist
> 0 && attract
&& winB
<= edge_t
+ resist
&& winB
>= edge_t
- resist
) {
1173 newY
= edge_t
- data
->winHeight
;
1179 if ((attract
&& winB
>= edge_b
- resist
&& winB
<= edge_b
+ resist
)
1180 || (dy
> 0 && winB
>= edge_b
&& winB
<= edge_b
+ resist
)) {
1181 newY
= edge_b
- data
->winHeight
;
1191 /* update window position */
1195 if (((dx
> 0 && data
->calcX
- data
->realX
> 0)
1196 || (dx
< 0 && data
->calcX
- data
->realX
< 0)) && !hresist
)
1199 if (((dy
> 0 && data
->calcY
- data
->realY
> 0)
1200 || (dy
< 0 && data
->calcY
- data
->realY
< 0)) && !vresist
)
1203 if (data
->realX
!= newX
|| data
->realY
!= newY
) {
1205 if (wPreferences
.move_display
== WDIS_NEW
1206 && !scr
->selected_windows
) {
1207 showPosition(wwin
, data
->realX
, data
->realY
);
1210 doWindowMove(wwin
, scr
->selected_windows
,
1211 newX
- wwin
->frame_x
,
1212 newY
- wwin
->frame_y
);
1215 drawFrames(wwin
, scr
->selected_windows
,
1216 data
->realX
- wwin
->frame_x
,
1217 data
->realY
- wwin
->frame_y
);
1220 if (!scr
->selected_windows
1221 && wPreferences
.move_display
== WDIS_FRAME_CENTER
) {
1223 moveGeometryDisplayCentered(scr
, newX
+ data
->winWidth
/2,
1224 newY
+ data
->winHeight
/2);
1229 drawFrames(wwin
, scr
->selected_windows
,
1230 newX
- wwin
->frame_x
,
1231 newY
- wwin
->frame_y
);
1234 if (!scr
->selected_windows
) {
1235 showPosition(wwin
, newX
, newY
);
1240 /* recalc relative window position */
1241 if (doResistance
&& (data
->realX
!= newX
|| data
->realY
!= newY
)) {
1242 updateResistance(wwin
, data
, newX
, newY
);
1250 #define _KS KEY_CONTROL_WINDOW_WEIGHT
1253 wKeyboardMoveResizeWindow(WWindow
*wwin
)
1255 WScreen
*scr
= wwin
->screen_ptr
;
1256 Window root
= scr
->root_win
;
1258 int w
= wwin
->frame
->core
->width
;
1259 int h
= wwin
->frame
->core
->height
;
1260 int scr_width
= wwin
->screen_ptr
->scr_width
;
1261 int scr_height
= wwin
->screen_ptr
->scr_height
;
1262 int vert_border
= wwin
->frame
->top_width
+ wwin
->frame
->bottom_width
;
1263 int src_x
= wwin
->frame_x
;
1264 int src_y
= wwin
->frame_y
;
1265 int done
,off_x
,off_y
,ww
,wh
;
1268 KeySym keysym
=NoSymbol
;
1270 KeyCode shiftl
,shiftr
,ctrll
,ctrlmode
;
1272 shiftl
= XKeysymToKeycode(dpy
, XK_Shift_L
);
1273 shiftr
= XKeysymToKeycode(dpy
, XK_Shift_R
);
1274 ctrll
= XKeysymToKeycode(dpy
, XK_Control_L
);
1275 ctrlmode
=done
=off_x
=off_y
=0;
1279 XGrabKeyboard(dpy
, root
, False
, GrabModeAsync
, GrabModeAsync
, CurrentTime
);
1281 if (!wwin
->flags
.selected
) {
1282 wUnselectWindows(scr
);
1285 XGrabPointer(dpy
, scr
->root_win
, True
, PointerMotionMask
1286 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
1287 GrabModeAsync
, None
, wCursor
[WCUR_DEFAULT
], CurrentTime
);
1289 if (wwin
->flags
.shaded
|| scr
->selected_windows
) {
1290 if(scr
->selected_windows
)
1291 drawFrames(wwin
,scr
->selected_windows
,off_x
,off_y
);
1292 else drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, w
, h
);
1293 if(!scr
->selected_windows
)
1294 mapPositionDisplay(wwin
, src_x
, src_y
, w
, h
);
1296 drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, w
, h
);
1305 WMMaskEvent(dpy
, KeyPressMask
| ButtonReleaseMask
1306 | ButtonPressMask
| ExposureMask
, &event
);
1307 if (wwin
->flags
.shaded
|| scr
->selected_windows
) {
1308 if(scr
->selected_windows
)
1309 drawFrames(wwin
,scr
->selected_windows
,off_x
,off_y
);
1310 else drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, w
, h
);
1311 /*** I HATE EDGE RESISTANCE - ]d ***/
1314 drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, ww
, wh
);
1318 showGeometry(wwin
, src_x
+off_x
, src_y
+off_y
, src_x
+off_x
+ww
, src_y
+off_y
+wh
,0);
1323 switch (event
.type
) {
1326 if (event
.xkey
.time
- lastTime
> 50) {
1327 kspeed
/=(1 + (event
.xkey
.time
- lastTime
)/100);
1333 if (kspeed
< _KS
) kspeed
= _KS
;
1334 lastTime
= event
.xkey
.time
;
1336 if (event
.xkey
.state
& ControlMask
&& !wwin
->flags
.shaded
) {
1338 wUnselectWindows(scr
);
1343 if (event
.xkey
.keycode
== shiftl
|| event
.xkey
.keycode
== shiftr
) {
1345 cycleGeometryDisplay(wwin
, src_x
+off_x
, src_y
+off_y
, ww
, wh
, 0);
1347 cyclePositionDisplay(wwin
, src_x
+off_x
, src_y
+off_y
, ww
, wh
);
1351 keysym
= XLookupKeysym(&event
.xkey
, 0);
1398 if (moment
!= RIGHT
)
1409 wWindowConstrainSize(wwin
, &ww
, &wh
);
1412 if (wPreferences
.ws_cycle
){
1413 if (src_x
+ off_x
+ ww
< 20){
1414 if(!scr
->current_workspace
) {
1415 wWorkspaceChange(scr
, scr
->workspace_count
-1);
1417 else wWorkspaceChange(scr
, scr
->current_workspace
-1);
1420 else if (src_x
+ off_x
+ 20 > scr_width
){
1421 if(scr
->current_workspace
== scr
->workspace_count
-1) {
1422 wWorkspaceChange(scr
, 0);
1424 else wWorkspaceChange(scr
, scr
->current_workspace
+1);
1429 if (src_x
+ off_x
+ ww
< 20)
1430 off_x
= 20 - ww
- src_x
;
1431 else if (src_x
+ off_x
+ 20 > scr_width
)
1432 off_x
= scr_width
- 20 - src_x
;
1435 if (src_y
+ off_y
+ wh
< 20) {
1436 off_y
= 20 - wh
- src_y
;
1438 else if (src_y
+ off_y
+ 20 > scr_height
) {
1439 off_y
= scr_height
- 20 - src_y
;
1448 WMHandleEvent(&event
);
1455 if (wwin
->flags
.shaded
&& !scr
->selected_windows
){
1456 moveGeometryDisplayCentered(scr
, src_x
+off_x
+ w
/2, src_y
+off_y
+ h
/2);
1460 unmapPositionDisplay(wwin
);
1461 mapGeometryDisplay(wwin
, src_x
+off_x
, src_y
+off_y
, ww
, wh
);
1463 else if(!scr
->selected_windows
){
1464 unmapGeometryDisplay(wwin
);
1465 mapPositionDisplay(wwin
, src_x
+off_x
, src_y
+off_y
, ww
, wh
);
1469 if (wwin
->flags
.shaded
|| scr
->selected_windows
) {
1470 if(scr
->selected_windows
)
1471 drawFrames(wwin
,scr
->selected_windows
,off_x
,off_y
);
1472 else drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, w
, h
);
1475 drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, ww
, wh
);
1480 showGeometry(wwin
, src_x
+off_x
, src_y
+off_y
, src_x
+off_x
+ww
, src_y
+off_y
+wh
,0);
1482 else if(!scr
->selected_windows
)
1483 showPosition(wwin
, src_x
+off_x
, src_y
+off_y
);
1487 scr
->keymove_tick
=0;
1489 WMDeleteTimerWithClientData(&looper);
1491 if (wwin
->flags
.shaded
|| scr
->selected_windows
) {
1492 if(scr
->selected_windows
)
1493 drawFrames(wwin
,scr
->selected_windows
,off_x
,off_y
);
1494 else drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, w
, h
);
1497 drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, ww
, wh
);
1501 showGeometry(wwin
, src_x
+off_x
, src_y
+off_y
, src_x
+off_x
+ww
, src_y
+off_y
+wh
,0);
1502 unmapGeometryDisplay(wwin
);
1505 unmapPositionDisplay(wwin
);
1506 XUngrabKeyboard(dpy
, CurrentTime
);
1507 XUngrabPointer(dpy
, CurrentTime
);
1511 if (wwin
->flags
.shaded
|| scr
->selected_windows
) {
1512 if (!scr
->selected_windows
) {
1513 wWindowMove(wwin
, src_x
+off_x
, src_y
+off_y
);
1514 wWindowSynthConfigureNotify(wwin
);
1517 WMBag
*bag
= scr
->selected_windows
;
1518 doWindowMove(wwin
,scr
->selected_windows
,off_x
,off_y
);
1519 for (i
= 0; i
< WMGetBagItemCount(bag
); i
++) {
1520 wWindowSynthConfigureNotify(WMGetFromBag(bag
, i
));
1524 if (wwin
->client
.width
!= ww
)
1525 wwin
->flags
.user_changed_width
= 1;
1527 if (wwin
->client
.height
!= wh
- vert_border
)
1528 wwin
->flags
.user_changed_height
= 1;
1530 wWindowConfigure(wwin
, src_x
+off_x
, src_y
+off_y
,
1531 ww
, wh
- vert_border
);
1532 wWindowSynthConfigureNotify(wwin
);
1534 wWindowChangeWorkspace(wwin
, scr
->current_workspace
);
1535 wSetFocusTo(scr
, wwin
);
1544 *----------------------------------------------------------------------
1545 * wMouseMoveWindow--
1546 * Move the named window and the other selected ones (if any),
1547 * interactively. Also shows the position of the window, if only one
1548 * window is being moved.
1549 * If the window is not on the selected window list, the selected
1550 * windows are deselected.
1551 * If shift is pressed during the operation, the position display
1552 * is changed to another type.
1555 * True if the window was moved, False otherwise.
1558 * The window(s) position is changed, and the client(s) are
1559 * notified about that.
1560 * The position display configuration may be changed.
1561 *----------------------------------------------------------------------
1564 wMouseMoveWindow(WWindow
*wwin
, XEvent
*ev
)
1566 WScreen
*scr
= wwin
->screen_ptr
;
1568 Window root
= scr
->root_win
;
1569 KeyCode shiftl
, shiftr
;
1573 /* This needs not to change while moving, else bad things can happen */
1574 int opaqueMove
= wPreferences
.opaque_move
;
1576 #ifdef GHOST_WINDOW_MOVE
1579 rimg
= InitGhostWindowMove(scr
);
1583 if (wPreferences
.opaque_move
&& !wPreferences
.use_saveunders
) {
1584 XSetWindowAttributes attr
;
1586 attr
.save_under
= True
;
1587 XChangeWindowAttributes(dpy
, wwin
->frame
->core
->window
,
1588 CWSaveUnder
, &attr
);
1592 initMoveData(wwin
, &moveData
);
1594 moveData
.mouseX
= ev
->xmotion
.x_root
;
1595 moveData
.mouseY
= ev
->xmotion
.y_root
;
1597 if (!wwin
->flags
.selected
) {
1598 /* this window is not selected, unselect others and move only wwin */
1599 wUnselectWindows(scr
);
1602 puts("Moving window");
1604 shiftl
= XKeysymToKeycode(dpy
, XK_Shift_L
);
1605 shiftr
= XKeysymToKeycode(dpy
, XK_Shift_R
);
1611 /* XWarpPointer() doesn't seem to generate Motion events, so
1612 we've got to simulate them */
1613 XQueryPointer(dpy
, root
, &junkw
, &junkw
, &event
.xmotion
.x_root
,
1614 &event
.xmotion
.y_root
, &junk
, &junk
,
1615 (unsigned *) &junk
);
1617 WMMaskEvent(dpy
, KeyPressMask
| ButtonMotionMask
1618 | ButtonReleaseMask
| ButtonPressMask
| ExposureMask
,
1621 if (event
.type
== MotionNotify
) {
1622 /* compress MotionNotify events */
1623 while (XCheckMaskEvent(dpy
, ButtonMotionMask
, &event
)) ;
1624 if (!checkMouseSamplingRate(&event
))
1628 switch (event
.type
) {
1630 if ((event
.xkey
.keycode
== shiftl
|| event
.xkey
.keycode
== shiftr
)
1631 && started
&& !scr
->selected_windows
) {
1634 drawFrames(wwin
, scr
->selected_windows
,
1635 moveData
.realX
- wwin
->frame_x
,
1636 moveData
.realY
- wwin
->frame_y
);
1639 if (wPreferences
.move_display
== WDIS_NEW
1640 && !scr
->selected_windows
) {
1641 showPosition(wwin
, moveData
.realX
, moveData
.realY
);
1644 cyclePositionDisplay(wwin
, moveData
.realX
, moveData
.realY
,
1645 moveData
.winWidth
, moveData
.winHeight
);
1647 if (wPreferences
.move_display
== WDIS_NEW
1648 && !scr
->selected_windows
) {
1650 showPosition(wwin
, moveData
.realX
, moveData
.realY
);
1654 drawFrames(wwin
, scr
->selected_windows
,
1655 moveData
.realX
- wwin
->frame_x
,
1656 moveData
.realY
- wwin
->frame_y
);
1663 updateWindowPosition(wwin
, &moveData
,
1664 scr
->selected_windows
== NULL
1665 && wPreferences
.edge_resistance
> 0,
1667 event
.xmotion
.x_root
,
1668 event
.xmotion
.y_root
);
1670 if (!warped
&& !wPreferences
.no_autowrap
) {
1671 int oldWorkspace
= scr
->current_workspace
;
1673 if (wPreferences
.move_display
== WDIS_NEW
1674 && !scr
->selected_windows
) {
1675 showPosition(wwin
, moveData
.realX
, moveData
.realY
);
1679 drawFrames(wwin
, scr
->selected_windows
,
1680 moveData
.realX
- wwin
->frame_x
,
1681 moveData
.realY
- wwin
->frame_y
);
1683 if (checkWorkspaceChange(wwin
, &moveData
, opaqueMove
)) {
1684 if (scr
->current_workspace
!= oldWorkspace
1685 && wPreferences
.edge_resistance
> 0
1686 && scr
->selected_windows
== NULL
)
1687 updateMoveData(wwin
, &moveData
);
1691 drawFrames(wwin
, scr
->selected_windows
,
1692 moveData
.realX
- wwin
->frame_x
,
1693 moveData
.realY
- wwin
->frame_y
);
1695 if (wPreferences
.move_display
== WDIS_NEW
1696 && !scr
->selected_windows
) {
1698 showPosition(wwin
, moveData
.realX
, moveData
.realY
);
1704 } else if (abs(ev
->xmotion
.x_root
- event
.xmotion
.x_root
) >= MOVE_THRESHOLD
1705 || abs(ev
->xmotion
.y_root
- event
.xmotion
.y_root
) >= MOVE_THRESHOLD
) {
1707 XChangeActivePointerGrab(dpy
, ButtonMotionMask
1708 | ButtonReleaseMask
| ButtonPressMask
,
1709 wCursor
[WCUR_MOVE
], CurrentTime
);
1711 XGrabKeyboard(dpy
, root
, False
, GrabModeAsync
, GrabModeAsync
,
1714 if (!scr
->selected_windows
)
1715 mapPositionDisplay(wwin
, moveData
.realX
, moveData
.realY
,
1716 moveData
.winWidth
, moveData
.winHeight
);
1718 if (started
&& !opaqueMove
)
1719 drawFrames(wwin
, scr
->selected_windows
, 0, 0);
1721 if (!opaqueMove
|| (wPreferences
.move_display
==WDIS_NEW
1722 && !scr
->selected_windows
)) {
1724 if (wPreferences
.move_display
==WDIS_NEW
)
1725 showPosition(wwin
, moveData
.realX
, moveData
.realY
);
1734 if (event
.xbutton
.button
!= ev
->xbutton
.button
)
1739 drawFrames(wwin
, scr
->selected_windows
,
1740 moveData
.realX
- wwin
->frame_x
,
1741 moveData
.realY
- wwin
->frame_y
);
1743 doWindowMove(wwin
, scr
->selected_windows
,
1744 moveData
.realX
- wwin
->frame_x
,
1745 moveData
.realY
- wwin
->frame_y
);
1747 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
1748 wWindowSynthConfigureNotify(wwin
);
1750 XUngrabKeyboard(dpy
, CurrentTime
);
1753 wWindowChangeWorkspace(wwin
, scr
->current_workspace
);
1754 wSetFocusTo(scr
, wwin
);
1756 if (wPreferences
.move_display
== WDIS_NEW
)
1757 showPosition(wwin
, moveData
.realX
, moveData
.realY
);
1759 if (!scr
->selected_windows
) {
1760 /* get rid of the geometry window */
1761 unmapPositionDisplay(wwin
);
1765 puts("End move window");
1771 if (started
&& !opaqueMove
) {
1772 drawFrames(wwin
, scr
->selected_windows
,
1773 moveData
.realX
- wwin
->frame_x
,
1774 moveData
.realY
- wwin
->frame_y
);
1776 WMHandleEvent(&event
);
1779 drawFrames(wwin
, scr
->selected_windows
,
1780 moveData
.realX
- wwin
->frame_x
,
1781 moveData
.realY
- wwin
->frame_y
);
1783 WMHandleEvent(&event
);
1789 if (wPreferences
.opaque_move
&& !wPreferences
.use_saveunders
) {
1790 XSetWindowAttributes attr
;
1793 attr
.save_under
= False
;
1794 XChangeWindowAttributes(dpy
, wwin
->frame
->core
->window
,
1795 CWSaveUnder
, &attr
);
1799 freeMoveData(&moveData
);
1806 #define HCONSTRAIN 2
1809 getResizeDirection(WWindow
*wwin
, int x
, int y
, int dx
, int dy
,
1812 int w
= wwin
->frame
->core
->width
- 1;
1813 int cw
= wwin
->frame
->resizebar_corner_width
;
1816 /* if not resizing through the resizebar */
1817 if (!(flags
& RESIZEBAR
)) {
1818 int xdir
= (abs(x
) < (wwin
->client
.width
/2)) ? LEFT
: RIGHT
;
1819 int ydir
= (abs(y
) < (wwin
->client
.height
/2)) ? UP
: DOWN
;
1820 if (abs(dx
) < 2 || abs(dy
) < 2) {
1821 if (abs(dy
) > abs(dx
))
1826 return (xdir
| ydir
);
1829 /* window is too narrow. allow diagonal resize */
1833 if (flags
& HCONSTRAIN
)
1838 return (LEFT
| ydir
);
1840 return (RIGHT
| ydir
);
1842 /* vertical resize */
1843 if ((x
> cw
) && (x
< w
- cw
))
1851 if ((abs(dy
) > 0) && !(flags
& HCONSTRAIN
))
1859 wMouseResizeWindow(WWindow
*wwin
, XEvent
*ev
)
1862 WScreen
*scr
= wwin
->screen_ptr
;
1863 Window root
= scr
->root_win
;
1864 int vert_border
= wwin
->frame
->top_width
+ wwin
->frame
->bottom_width
;
1865 int fw
= wwin
->frame
->core
->width
;
1866 int fh
= wwin
->frame
->core
->height
;
1867 int fx
= wwin
->frame_x
;
1868 int fy
= wwin
->frame_y
;
1869 int is_resizebar
= (wwin
->frame
->resizebar
1870 && ev
->xany
.window
==wwin
->frame
->resizebar
->window
);
1874 int rw
= fw
, rh
= fh
;
1875 int rx1
, ry1
, rx2
, ry2
;
1877 KeyCode shiftl
, shiftr
;
1884 if (wwin
->flags
.shaded
) {
1885 wwarning("internal error: tryein");
1888 orig_x
= ev
->xbutton
.x_root
;
1889 orig_y
= ev
->xbutton
.y_root
;
1893 puts("Resizing window");
1896 wUnselectWindows(scr
);
1901 shiftl
= XKeysymToKeycode(dpy
, XK_Shift_L
);
1902 shiftr
= XKeysymToKeycode(dpy
, XK_Shift_R
);
1903 if (!WFLAGP(wwin
, no_titlebar
))
1904 h
= WMFontHeight(wwin
->screen_ptr
->title_font
) + TITLEBAR_EXTRA_HEIGHT
;
1908 WMMaskEvent(dpy
, KeyPressMask
| ButtonMotionMask
| ButtonReleaseMask
1909 | ButtonPressMask
| ExposureMask
, &event
);
1911 if (!checkMouseSamplingRate(&event
))
1914 switch (event
.type
) {
1916 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
1917 if ((event
.xkey
.keycode
== shiftl
|| event
.xkey
.keycode
== shiftr
)
1919 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1920 cycleGeometryDisplay(wwin
, fx
, fy
, fw
, fh
, res
);
1921 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1923 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
1937 dw
= orig_x
- event
.xmotion
.x_root
;
1938 else if (res
& RIGHT
)
1939 dw
= event
.xmotion
.x_root
- orig_x
;
1941 dh
= orig_y
- event
.xmotion
.y_root
;
1942 else if (res
& DOWN
)
1943 dh
= event
.xmotion
.y_root
- orig_y
;
1945 orig_x
= event
.xmotion
.x_root
;
1946 orig_y
= event
.xmotion
.y_root
;
1951 fh
= rh
- vert_border
;
1952 wWindowConstrainSize(wwin
, &fw
, &fh
);
1956 else if (res
& RIGHT
)
1960 else if (res
& DOWN
)
1962 } else if (abs(orig_x
- event
.xmotion
.x_root
) >= MOVE_THRESHOLD
1963 || abs(orig_y
- event
.xmotion
.y_root
) >= MOVE_THRESHOLD
) {
1968 XTranslateCoordinates(dpy
, root
, wwin
->frame
->core
->window
,
1969 orig_x
, orig_y
, &tx
, &ty
, &junkw
);
1971 /* check if resizing through resizebar */
1977 if (is_resizebar
&& ((ev
->xbutton
.state
& ShiftMask
)
1978 || abs(orig_y
- event
.xmotion
.y_root
) < HRESIZE_THRESHOLD
))
1979 flags
|= HCONSTRAIN
;
1981 res
= getResizeDirection(wwin
, tx
, ty
,
1982 orig_x
- event
.xmotion
.x_root
,
1983 orig_y
- event
.xmotion
.y_root
, flags
);
1985 XChangeActivePointerGrab(dpy
, ButtonMotionMask
1986 | ButtonReleaseMask
| ButtonPressMask
,
1987 wCursor
[WCUR_RESIZE
], CurrentTime
);
1988 XGrabKeyboard(dpy
, root
, False
, GrabModeAsync
, GrabModeAsync
,
1993 /* Draw the resize frame for the first time. */
1994 mapGeometryDisplay(wwin
, fx
, fy
, fw
, fh
);
1996 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1998 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
2003 if (wPreferences
.size_display
== WDIS_FRAME_CENTER
) {
2004 drawTransparentFrame(wwin
, orig_fx
, orig_fy
,
2006 moveGeometryDisplayCentered(scr
, fx
+ fw
/ 2, fy
+ fh
/ 2);
2007 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
2009 drawTransparentFrame(wwin
, orig_fx
, orig_fy
,
2011 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
2013 if (fh
!= orig_fh
|| fw
!= orig_fw
) {
2014 if (wPreferences
.size_display
== WDIS_NEW
) {
2015 showGeometry(wwin
, orig_fx
, orig_fy
, orig_fx
+ orig_fw
,
2016 orig_fy
+ orig_fh
, res
);
2018 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
2027 if (event
.xbutton
.button
!= ev
->xbutton
.button
)
2031 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
2033 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
2035 XUngrabKeyboard(dpy
, CurrentTime
);
2036 unmapGeometryDisplay(wwin
);
2039 if (wwin
->client
.width
!= fw
)
2040 wwin
->flags
.user_changed_width
= 1;
2042 if (wwin
->client
.height
!= fh
- vert_border
)
2043 wwin
->flags
.user_changed_height
= 1;
2045 wWindowConfigure(wwin
, fx
, fy
, fw
, fh
- vert_border
);
2048 puts("End resize window");
2053 WMHandleEvent(&event
);
2068 wUnselectWindows(WScreen
*scr
)
2072 if (!scr
->selected_windows
)
2075 while (WMGetBagItemCount(scr
->selected_windows
)) {
2076 wwin
= WMGetFromBag(scr
->selected_windows
, 0);
2077 if (wwin
->flags
.miniaturized
&& wwin
->icon
&& wwin
->icon
->selected
)
2078 wIconSelect(wwin
->icon
);
2080 wSelectWindow(wwin
, False
);
2082 WMFreeBag(scr
->selected_windows
);
2083 scr
->selected_windows
= NULL
;
2088 selectWindowsInside(WScreen
*scr
, int x1
, int y1
, int x2
, int y2
)
2092 /* select the windows and put them in the selected window list */
2093 tmpw
= scr
->focused_window
;
2094 while (tmpw
!= NULL
) {
2095 if (!(tmpw
->flags
.miniaturized
|| tmpw
->flags
.hidden
)) {
2096 if ((tmpw
->frame
->workspace
== scr
->current_workspace
2097 || IS_OMNIPRESENT(tmpw
))
2098 && (tmpw
->frame_x
>= x1
) && (tmpw
->frame_y
>= y1
)
2099 && (tmpw
->frame
->core
->width
+ tmpw
->frame_x
<= x2
)
2100 && (tmpw
->frame
->core
->height
+ tmpw
->frame_y
<= y2
)) {
2101 wSelectWindow(tmpw
, True
);
2110 wSelectWindows(WScreen
*scr
, XEvent
*ev
)
2113 Window root
= scr
->root_win
;
2114 GC gc
= scr
->frame_gc
;
2115 int xp
= ev
->xbutton
.x_root
;
2116 int yp
= ev
->xbutton
.y_root
;
2118 int nx
= xp
, ny
= yp
, ox
= xp
, oy
= yp
, update_selection
= 0;
2119 XSegment segments
[8]; /* 8 segments is the most possible */
2120 /* it may be beneficial to use */
2121 /* XDrawRectangle for 8 segment case */
2126 puts("Selecting windows");
2128 if (XGrabPointer(dpy
, scr
->root_win
, True
, PointerMotionMask
2129 | ButtonMotionMask
| ButtonReleaseMask
| ButtonPressMask
2130 | EnterWindowMask
| LeaveWindowMask
, GrabModeAsync
,
2131 GrabModeAsync
, None
, wCursor
[WCUR_DEFAULT
],
2132 CurrentTime
) != Success
) {
2137 wUnselectWindows(scr
);
2140 update_selection
= 0;
2142 WMMaskEvent(dpy
, ButtonReleaseMask
| PointerMotionMask
| LeaveWindowMask
2143 | EnterWindowMask
| ButtonPressMask
,
2146 if (!checkMouseSamplingRate(&event
))
2150 switch (event
.type
) {
2154 dbputs("got Enter/LeaveNotify in selection");
2156 nx
= event
.xcrossing
.x_root
;
2157 ny
= event
.xcrossing
.y_root
;
2158 update_selection
= 1;
2164 dbputs("got motionevent in selection");
2166 nx
= event
.xmotion
.x_root
;
2167 ny
= event
.xmotion
.y_root
;
2168 update_selection
= 1;
2175 if (event
.xbutton
.button
!= ev
->xbutton
.button
)
2178 if(nx
> xp
) w
= nx
- xp
;
2184 if(ny
> yp
) h
= ny
- yp
;
2190 XDrawRectangle(dpy
, root
, gc
, xp
, yp
, w
, h
);
2192 XUngrabPointer(dpy
, CurrentTime
);
2193 selectWindowsInside(scr
, xp
, yp
, w
+ xp
, h
+ yp
);
2196 wKWMSelectRootRegion(scr
, xp
, yp
, w
, h
,
2197 event
.xbutton
.state
& ControlMask
);
2198 #endif /* KWM_HINTS */
2201 dbputs("End window selection");
2207 dbputs("unknown event");
2208 dbprintf("type: %u\n", event
.type
);
2210 WMHandleEvent(&event
);
2214 if(update_selection
) {
2215 /* stuff to change for movement along X axis */
2218 /* erase old vertical line */
2219 /* only if old vertical line exists */
2220 /* and only if its different from other vertical line */
2221 if(yp
!= oy
&& ox
!= xp
) {
2222 segments
[nsegs
].x1
= ox
;
2223 segments
[nsegs
].y1
= yp
;
2224 segments
[nsegs
].x2
= ox
;
2225 segments
[nsegs
].y2
= oy
;
2229 /* draw new vertical line */
2230 /* only if new vertical line exists */
2231 /* and only if its different from the other vertical line */
2232 if(yp
!= ny
&& nx
!= xp
) {
2233 segments
[nsegs
].x1
= nx
;
2234 segments
[nsegs
].y1
= yp
;
2235 segments
[nsegs
].x2
= nx
;
2236 segments
[nsegs
].y2
= ny
;
2240 /* difference along x axis from old to new on ny horizontal */
2241 /* only if our mouse doesnt move along Y, otherwise this gets */
2242 /* done elsewhere */
2243 if(ny
== oy
&& nx
!= xp
) {
2244 segments
[nsegs
].x1
= ox
;
2245 segments
[nsegs
].y1
= ny
;
2246 segments
[nsegs
].x2
= nx
;
2247 segments
[nsegs
].y2
= ny
;
2251 /* difference along x axis from old to new on yp horizontal */
2252 segments
[nsegs
].x1
= nx
;
2253 segments
[nsegs
].y1
= yp
;
2254 segments
[nsegs
].x2
= ox
;
2255 segments
[nsegs
].y2
= yp
;
2261 /* now for stuff to change for movement along Y axis */
2264 /* erase old horizontal line */
2265 /* only if old horizontal line exists */
2266 /* and only if its different from other horizontal line */
2267 if(xp
!= ox
&& oy
!= yp
) {
2268 segments
[nsegs
].x1
= ox
;
2269 segments
[nsegs
].y1
= oy
;
2270 segments
[nsegs
].x2
= xp
;
2271 segments
[nsegs
].y2
= oy
;
2275 /* draw new horizontal line */
2276 /* only if horizontal line exists, and if its different from other */
2277 if(xp
!= nx
&& ny
!= yp
) {
2278 segments
[nsegs
].x1
= nx
;
2279 segments
[nsegs
].y1
= ny
;
2280 segments
[nsegs
].x2
= xp
;
2281 segments
[nsegs
].y2
= ny
;
2285 /* difference along y axis from old to new on nx vertical */
2286 /* only if no movement along x axis */
2287 /* and only if we dont have duplicate lines */
2288 if(nx
== ox
&& nx
!= xp
) {
2289 segments
[nsegs
].x1
= nx
;
2290 segments
[nsegs
].y1
= oy
;
2291 segments
[nsegs
].x2
= nx
;
2292 segments
[nsegs
].y2
= ny
;
2296 /* difference along y axis from old to new on xp vertical */
2297 segments
[nsegs
].x1
= xp
;
2298 segments
[nsegs
].y1
= oy
;
2299 segments
[nsegs
].x2
= xp
;
2300 segments
[nsegs
].y2
= ny
;
2306 XDrawSegments(dpy
, root
, gc
, segments
, nsegs
);
2313 InteractivePlaceWindow(WWindow
*wwin
, int *x_ret
, int *y_ret
,
2314 unsigned width
, unsigned height
)
2316 WScreen
*scr
= wwin
->screen_ptr
;
2317 Window root
= scr
->root_win
;
2320 KeyCode shiftl
, shiftr
;
2324 if (XGrabPointer(dpy
, root
, True
, PointerMotionMask
| ButtonPressMask
,
2325 GrabModeAsync
, GrabModeAsync
, None
,
2326 wCursor
[WCUR_DEFAULT
], CurrentTime
) != Success
) {
2331 if (!WFLAGP(wwin
, no_titlebar
)) {
2332 h
= WMFontHeight(scr
->title_font
) + TITLEBAR_EXTRA_HEIGHT
;
2335 if (!WFLAGP(wwin
, no_resizebar
)) {
2336 height
+= RESIZEBAR_HEIGHT
;
2338 XGrabKeyboard(dpy
, root
, False
, GrabModeAsync
, GrabModeAsync
, CurrentTime
);
2339 XQueryPointer(dpy
, root
, &junkw
, &junkw
, &x
, &y
, &junk
, &junk
,
2340 (unsigned *) &junk
);
2341 mapPositionDisplay(wwin
, x
- width
/2, y
- h
/2, width
, height
);
2343 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
2345 shiftl
= XKeysymToKeycode(dpy
, XK_Shift_L
);
2346 shiftr
= XKeysymToKeycode(dpy
, XK_Shift_R
);
2348 WMMaskEvent(dpy
, PointerMotionMask
|ButtonPressMask
|ExposureMask
|KeyPressMask
,
2351 if (!checkMouseSamplingRate(&event
))
2354 switch (event
.type
) {
2356 if ((event
.xkey
.keycode
== shiftl
)
2357 || (event
.xkey
.keycode
== shiftr
)) {
2358 drawTransparentFrame(wwin
,
2359 x
- width
/2, y
- h
/2, width
, height
);
2360 cyclePositionDisplay(wwin
,
2361 x
- width
/2, y
- h
/2, width
, height
);
2362 drawTransparentFrame(wwin
,
2363 x
- width
/2, y
- h
/2, width
, height
);
2368 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
2370 x
= event
.xmotion
.x_root
;
2371 y
= event
.xmotion
.y_root
;
2373 if (wPreferences
.move_display
== WDIS_FRAME_CENTER
)
2374 moveGeometryDisplayCentered(scr
, x
, y
+ (height
- h
) / 2);
2376 showPosition(wwin
, x
- width
/2, y
- h
/2);
2378 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
2383 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
2385 *x_ret
= x
- width
/2;
2387 XUngrabPointer(dpy
, CurrentTime
);
2388 XUngrabKeyboard(dpy
, CurrentTime
);
2389 /* get rid of the geometry window */
2390 unmapPositionDisplay(wwin
);
2394 WMHandleEvent(&event
);