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
;
71 wGetGeometryWindowSize(WScreen
*scr
, unsigned int *width
,
74 *width
= WMWidthOfString(scr
->info_text_font
, "-8888 x -8888", 13);
76 *height
= (6 * WMFontHeight(scr
->info_text_font
)) / 4 - 1;
81 *----------------------------------------------------------------------
82 * moveGeometryDisplayCentered
84 * routine that moves the geometry/position window on scr so it is
85 * centered over the given coordinates (x,y). Also the window position
86 * is clamped so it stays on the screen at all times.
87 *----------------------------------------------------------------------
90 moveGeometryDisplayCentered(WScreen
*scr
, int x
, int y
)
92 x
-= scr
->geometry_display_width
/ 2;
93 y
-= scr
->geometry_display_height
/ 2;
97 else if (x
> (scr
->scr_width
- scr
->geometry_display_width
- 3))
98 x
= scr
->scr_width
- scr
->geometry_display_width
- 3;
102 else if (y
> (scr
->scr_height
- scr
->geometry_display_height
- 3))
103 y
= scr
->scr_height
- scr
->geometry_display_height
- 3;
105 XMoveWindow(dpy
, scr
->geometry_display
, x
, y
);
110 showPosition(WWindow
*wwin
, int x
, int y
)
112 WScreen
*scr
= wwin
->screen_ptr
;
113 GC gc
= scr
->info_text_gc
;
117 if (wPreferences
.move_display
== WDIS_NEW
) {
119 int width
= wwin
->frame
->core
->width
;
120 int height
= wwin
->frame
->core
->height
;
122 GC lgc
= scr
->line_gc
;
123 XSetForeground(dpy
, lgc
, scr
->line_pixel
);
124 sprintf(num
, "%i", x
);
126 XDrawLine(dpy
, scr
->root_win
, lgc
, 0, y
-1, scr
->scr_width
, y
-1);
127 XDrawLine(dpy
, scr
->root_win
, lgc
, 0, y
+height
+2, scr
->scr_width
,
129 XDrawLine(dpy
, scr
->root_win
, lgc
, x
-1, 0, x
-1, scr
->scr_height
);
130 XDrawLine(dpy
, scr
->root_win
, lgc
, x
+width
+2, 0, x
+width
+2,
134 XClearArea(dpy
, scr
->geometry_display
, 1, 1,
135 scr
->geometry_display_width
-2, scr
->geometry_display_height
-2,
137 sprintf(num
, "%+i %-+i", x
, y
);
138 fw
= WMWidthOfString(scr
->info_text_font
, num
, strlen(num
));
140 XSetForeground(dpy
, gc
, scr
->black_pixel
);
142 fh
= WMFontHeight(scr
->info_text_font
);
143 WMDrawString(scr
->wmscreen
, scr
->geometry_display
, gc
,
145 (scr
->geometry_display_width
- 2 - fw
) / 2,
146 (scr
->geometry_display_height
-fh
)/2, num
, strlen(num
));
147 wDrawBevel(scr
->geometry_display
, scr
->geometry_display_width
+1,
148 scr
->geometry_display_height
+1,
149 scr
->widget_texture
, WREL_RAISED
);
155 cyclePositionDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
)
157 WScreen
*scr
= wwin
->screen_ptr
;
159 wPreferences
.move_display
++;
160 wPreferences
.move_display
%= NUM_DISPLAYS
;
162 if (wPreferences
.move_display
== WDIS_NEW
) {
163 XUnmapWindow(dpy
, scr
->geometry_display
);
165 if (wPreferences
.move_display
== WDIS_CENTER
) {
166 moveGeometryDisplayCentered(scr
,
167 scr
->scr_width
/2, scr
->scr_height
/2);
168 } else if (wPreferences
.move_display
== WDIS_TOPLEFT
) {
169 moveGeometryDisplayCentered(scr
, 1, 1);
170 } else if (wPreferences
.move_display
== WDIS_FRAME_CENTER
) {
171 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
173 XMapRaised(dpy
, scr
->geometry_display
);
179 mapPositionDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
)
181 WScreen
*scr
= wwin
->screen_ptr
;
183 if (wPreferences
.move_display
== WDIS_NEW
) {
185 } else if (wPreferences
.move_display
== WDIS_CENTER
) {
186 moveGeometryDisplayCentered(scr
, scr
->scr_width
/ 2,
187 scr
->scr_height
/ 2);
188 } else if (wPreferences
.move_display
== WDIS_TOPLEFT
) {
189 moveGeometryDisplayCentered(scr
, 1, 1);
190 } else if (wPreferences
.move_display
== WDIS_FRAME_CENTER
) {
191 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
193 XMapRaised(dpy
, scr
->geometry_display
);
194 showPosition(wwin
, x
, y
);
197 #define unmapPositionDisplay(w) \
198 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
202 showGeometry(WWindow
*wwin
, int x1
, int y1
, int x2
, int y2
, int direction
)
204 WScreen
*scr
= wwin
->screen_ptr
;
205 Window root
= scr
->root_win
;
206 GC gc
= scr
->line_gc
;
207 int ty
, by
, my
, x
, y
, mx
, s
;
212 ty
= y1
+ wwin
->frame
->top_width
;
213 by
= y2
- wwin
->frame
->bottom_width
;
214 fw
= WMWidthOfString(scr
->info_text_font
, "8888", 4);
215 fh
= WMFontHeight(scr
->info_text_font
);
217 if (wPreferences
.size_display
== WDIS_NEW
) {
218 XSetForeground(dpy
, gc
, scr
->line_pixel
);
220 /* vertical geometry */
221 if (((direction
& LEFT
) && (x2
< scr
->scr_width
- fw
)) || (x1
< fw
)) {
232 segment
[0].x1
= x
- (s
+ 6); segment
[0].y1
= ty
;
233 segment
[0].x2
= x
- (s
- 10); segment
[0].y2
= ty
;
236 segment
[1].x1
= x
- (s
- 2); segment
[1].y1
= ty
+ 1;
237 segment
[1].x2
= x
- (s
- 5); segment
[1].y2
= ty
+ 7;
239 segment
[2].x1
= x
- (s
- 2); segment
[2].y1
= ty
+ 1;
240 segment
[2].x2
= x
- (s
+ 1); segment
[2].y2
= ty
+ 7;
243 segment
[3].x1
= x
- (s
- 2); segment
[3].y1
= ty
+ 1;
244 segment
[3].x2
= x
- (s
- 2); segment
[3].y2
= my
- fh
/2 - 1;
246 XDrawSegments(dpy
, root
, gc
, segment
, 4);
254 segment
[1].y1
= by
- 1;
255 segment
[1].y2
= by
- 7;
257 segment
[2].y1
= by
- 1;
258 segment
[2].y2
= by
- 7;
261 segment
[3].y1
= my
+ fh
/2 + 2;
262 segment
[3].y2
= by
- 1;
264 XDrawSegments(dpy
, root
, gc
, segment
, 4);
266 sprintf(num
, "%i", (by
- ty
- wwin
->normal_hints
->base_height
) /
267 wwin
->normal_hints
->height_inc
);
268 fw
= WMWidthOfString(scr
->info_text_font
, num
, strlen(num
));
270 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
272 /* Display the height. */
273 WMDrawString(scr
->wmscreen
, root
, gc
, scr
->info_text_font
,
274 x
- s
+ 3 - fw
/2, my
- fh
/2 + 1, num
, strlen(num
));
275 XSetForeground(dpy
, gc
, scr
->line_pixel
);
276 /* horizontal geometry */
284 mx
= x1
+ (x2
- x1
)/2;
285 sprintf(num
, "%i", (x2
- x1
- wwin
->normal_hints
->base_width
) /
286 wwin
->normal_hints
->width_inc
);
287 fw
= WMWidthOfString(scr
->info_text_font
, num
, strlen(num
));
291 segment
[0].x1
= x1
; segment
[0].y1
= y
- (s
+ 6);
292 segment
[0].x2
= x1
; segment
[0].y2
= y
- (s
- 10);
295 segment
[1].x1
= x1
+ 7; segment
[1].y1
= y
- (s
+ 1);
296 segment
[1].x2
= x1
+ 1; segment
[1].y2
= y
- (s
- 2);
298 segment
[2].x1
= x1
+ 1; segment
[2].y1
= y
- (s
- 2);
299 segment
[2].x2
= x1
+ 7; segment
[2].y2
= y
- (s
- 5);
302 segment
[3].x1
= x1
+ 1; segment
[3].y1
= y
- (s
- 2);
303 segment
[3].x2
= mx
- fw
/2 - 2; segment
[3].y2
= y
- (s
- 2);
305 XDrawSegments(dpy
, root
, gc
, segment
, 4);
309 segment
[0].x1
= x2
+ 1;
310 segment
[0].x2
= x2
+ 1;
313 segment
[1].x1
= x2
- 6;
317 segment
[2].x2
= x2
- 6;
320 segment
[3].x1
= mx
+ fw
/2 + 2;
323 XDrawSegments(dpy
, root
, gc
, segment
, 4);
325 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
327 /* Display the width. */
328 WMDrawString(scr
->wmscreen
, root
, gc
, scr
->info_text_font
,
329 mx
- fw
/2 + 1, y
- s
- fh
/2 + 1, num
, strlen(num
));
331 XClearArea(dpy
, scr
->geometry_display
, 1, 1,
332 scr
->geometry_display_width
-2, scr
->geometry_display_height
-2,
334 sprintf(num
, "%i x %-i", (x2
- x1
- wwin
->normal_hints
->base_width
)
335 / wwin
->normal_hints
->width_inc
,
336 (by
- ty
- wwin
->normal_hints
->base_height
)
337 / wwin
->normal_hints
->height_inc
);
338 fw
= WMWidthOfString(scr
->info_text_font
, num
, strlen(num
));
340 XSetForeground(dpy
, scr
->info_text_gc
, scr
->black_pixel
);
342 /* Display the height. */
343 WMDrawString(scr
->wmscreen
, scr
->geometry_display
, scr
->info_text_gc
,
345 (scr
->geometry_display_width
-fw
)/2,
346 (scr
->geometry_display_height
-fh
)/2, num
, strlen(num
));
347 wDrawBevel(scr
->geometry_display
, scr
->geometry_display_width
+1,
348 scr
->geometry_display_height
+1,
349 scr
->widget_texture
, WREL_RAISED
);
355 cycleGeometryDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
, int dir
)
357 WScreen
*scr
= wwin
->screen_ptr
;
359 wPreferences
.size_display
++;
360 wPreferences
.size_display
%= NUM_DISPLAYS
;
362 if (wPreferences
.size_display
== WDIS_NEW
) {
363 XUnmapWindow(dpy
, scr
->geometry_display
);
365 if (wPreferences
.size_display
== WDIS_CENTER
) {
366 moveGeometryDisplayCentered(scr
,
367 scr
->scr_width
/ 2, scr
->scr_height
/ 2);
368 } else if (wPreferences
.size_display
== WDIS_TOPLEFT
) {
369 moveGeometryDisplayCentered(scr
, 1, 1);
370 } else if (wPreferences
.size_display
== WDIS_FRAME_CENTER
) {
371 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
373 XMapRaised(dpy
, scr
->geometry_display
);
374 showGeometry(wwin
, x
, y
, x
+ w
, y
+ h
, dir
);
380 mapGeometryDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
)
382 WScreen
*scr
= wwin
->screen_ptr
;
384 if (wPreferences
.size_display
== WDIS_NEW
)
387 if (wPreferences
.size_display
== WDIS_CENTER
) {
388 moveGeometryDisplayCentered(scr
, scr
->scr_width
/ 2,
389 scr
->scr_height
/ 2);
390 } else if (wPreferences
.size_display
== WDIS_TOPLEFT
) {
391 moveGeometryDisplayCentered(scr
, 1, 1);
392 } else if (wPreferences
.size_display
== WDIS_FRAME_CENTER
) {
393 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
395 XMapRaised(dpy
, scr
->geometry_display
);
396 showGeometry(wwin
, x
, y
, x
+ w
, y
+ h
, 0);
399 #define unmapGeometryDisplay(w) \
400 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
404 doWindowMove(WWindow
*wwin
, WMBag
*bag
, int dx
, int dy
)
408 int scr_width
= wwin
->screen_ptr
->scr_width
;
409 int scr_height
= wwin
->screen_ptr
->scr_height
;
411 if (!bag
|| !WMGetBagItemCount(bag
)) {
412 wWindowMove(wwin
, wwin
->frame_x
+ dx
, wwin
->frame_y
+ dy
);
415 for (i
= 0; i
< WMGetBagItemCount(bag
); i
++) {
416 tmpw
= WMGetFromBag(bag
, i
);
417 x
= tmpw
->frame_x
+ dx
;
418 y
= tmpw
->frame_y
+ dy
;
420 /* don't let windows become unreachable */
422 if (x
+ (int)tmpw
->frame
->core
->width
< 20)
423 x
= 20 - (int)tmpw
->frame
->core
->width
;
424 else if (x
+ 20 > scr_width
)
427 if (y
+ (int)tmpw
->frame
->core
->height
< 20)
428 y
= 20 - (int)tmpw
->frame
->core
->height
;
429 else if (y
+ 20 > scr_height
)
432 wWindowMove(tmpw
, x
, y
);
439 drawTransparentFrame(WWindow
*wwin
, int x
, int y
, int width
, int height
)
441 Window root
= wwin
->screen_ptr
->root_win
;
442 GC gc
= wwin
->screen_ptr
->frame_gc
;
446 if (!WFLAGP(wwin
, no_titlebar
) && !wwin
->flags
.shaded
) {
447 h
= WMFontHeight(wwin
->screen_ptr
->title_font
) + TITLEBAR_EXTRA_HEIGHT
;
449 if (!WFLAGP(wwin
, no_resizebar
) && !wwin
->flags
.shaded
) {
450 /* Can't use wwin-frame->bottom_width because, in some cases
451 (e.g. interactive placement), frame does not point to anything. */
452 bottom
= RESIZEBAR_HEIGHT
- 1;
454 XDrawRectangle(dpy
, root
, gc
, x
, y
, width
+ 1, height
+ 1);
457 XDrawLine(dpy
, root
, gc
, x
+ 1, y
+ h
, x
+ width
+ 1, y
+ h
);
460 XDrawLine(dpy
, root
, gc
, x
+ 1,
463 y
+ height
- bottom
);
469 drawFrames(WWindow
*wwin
, WMBag
*bag
, int dx
, int dy
)
472 int scr_width
= wwin
->screen_ptr
->scr_width
;
473 int scr_height
= wwin
->screen_ptr
->scr_height
;
478 x
= wwin
->frame_x
+ dx
;
479 y
= wwin
->frame_y
+ dy
;
481 drawTransparentFrame(wwin
, x
, y
,
482 wwin
->frame
->core
->width
,
483 wwin
->frame
->core
->height
);
487 for (i
= 0; i
< WMGetBagItemCount(bag
); i
++) {
488 tmpw
= WMGetFromBag(bag
, i
);
489 x
= tmpw
->frame_x
+ dx
;
490 y
= tmpw
->frame_y
+ dy
;
492 /* don't let windows become unreachable */
494 if (x
+ (int)tmpw
->frame
->core
->width
< 20)
495 x
= 20 - (int)tmpw
->frame
->core
->width
;
496 else if (x
+ 20 > scr_width
)
499 if (y
+ (int)tmpw
->frame
->core
->height
< 20)
500 y
= 20 - (int)tmpw
->frame
->core
->height
;
501 else if (y
+ 20 > scr_height
)
504 drawTransparentFrame(tmpw
, x
, y
, tmpw
->frame
->core
->width
,
505 tmpw
->frame
->core
->height
);
518 while (XCheckMaskEvent(dpy
, ButtonMotionMask
, &ev
)) ;
523 crossWorkspace(WScreen
*scr
, WWindow
*wwin
, int opaque_move
,
524 int new_workspace
, int rewind
)
526 /* do not let window be unmapped */
528 wwin
->flags
.changing_workspace
= 1;
529 wWindowChangeWorkspace(wwin
, new_workspace
);
531 /* go to new workspace */
532 wWorkspaceChange(scr
, new_workspace
);
534 wwin
->flags
.changing_workspace
= 0;
537 XWarpPointer(dpy
, None
, None
, 0, 0, 0, 0, scr
->scr_width
- 20, 0);
539 XWarpPointer(dpy
, None
, None
, 0, 0, 0, 0, -(scr
->scr_width
- 20), 0);
544 XGrabPointer(dpy
, scr
->root_win
, True
, PointerMotionMask
545 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
546 GrabModeAsync
, None
, wCursor
[WCUR_MOVE
], CurrentTime
);
554 /* arrays of WWindows sorted by the respective border position */
555 WWindow
**topList
; /* top border */
556 WWindow
**leftList
; /* left border */
557 WWindow
**rightList
; /* right border */
558 WWindow
**bottomList
; /* bottom border */
561 /* index of window in the above lists indicating the relative position
562 * of the window with the others */
568 int rubCount
; /* for workspace switching */
570 int winWidth
, winHeight
; /* width/height of the window */
571 int realX
, realY
; /* actual position of the window */
572 int calcX
, calcY
; /* calculated position of window */
573 int omouseX
, omouseY
; /* old mouse position */
574 int mouseX
, mouseY
; /* last known position of the pointer */
577 #define WTOP(w) (w)->frame_y
578 #define WLEFT(w) (w)->frame_x
579 #define WRIGHT(w) ((w)->frame_x + (int)(w)->frame->core->width + FRAME_BORDER_WIDTH)
580 #define WBOTTOM(w) ((w)->frame_y + (int)(w)->frame->core->height + FRAME_BORDER_WIDTH)
583 compareWTop(const void *a
, const void *b
)
585 WWindow
*wwin1
= *(WWindow
**)a
;
586 WWindow
*wwin2
= *(WWindow
**)b
;
588 if (WTOP(wwin1
) > WTOP(wwin2
))
590 else if (WTOP(wwin1
) < WTOP(wwin2
))
598 compareWLeft(const void *a
, const void *b
)
600 WWindow
*wwin1
= *(WWindow
**)a
;
601 WWindow
*wwin2
= *(WWindow
**)b
;
603 if (WLEFT(wwin1
) > WLEFT(wwin2
))
605 else if (WLEFT(wwin1
) < WLEFT(wwin2
))
613 compareWRight(const void *a
, const void *b
)
615 WWindow
*wwin1
= *(WWindow
**)a
;
616 WWindow
*wwin2
= *(WWindow
**)b
;
618 if (WRIGHT(wwin1
) < WRIGHT(wwin2
))
620 else if (WRIGHT(wwin1
) > WRIGHT(wwin2
))
629 compareWBottom(const void *a
, const void *b
)
631 WWindow
*wwin1
= *(WWindow
**)a
;
632 WWindow
*wwin2
= *(WWindow
**)b
;
634 if (WBOTTOM(wwin1
) < WBOTTOM(wwin2
))
636 else if (WBOTTOM(wwin1
) > WBOTTOM(wwin2
))
644 updateResistance(WWindow
*wwin
, MoveData
*data
, int newX
, int newY
)
647 int newX2
= newX
+ data
->winWidth
;
648 int newY2
= newY
+ data
->winHeight
;
651 if (newX
< data
->realX
) {
652 if (data
->rightIndex
> 0
653 && newX
< WRIGHT(data
->rightList
[data
->rightIndex
-1])) {
655 } else if (data
->leftIndex
<= data
->count
-1
656 && newX2
<= WLEFT(data
->leftList
[data
->leftIndex
])) {
659 } else if (newX
> data
->realX
) {
660 if (data
->leftIndex
> 0
661 && newX2
> WLEFT(data
->leftList
[data
->leftIndex
-1])) {
663 } else if (data
->rightIndex
<= data
->count
-1
664 && newX
>= WRIGHT(data
->rightList
[data
->rightIndex
])) {
670 if (newY
< data
->realY
) {
671 if (data
->bottomIndex
> 0
672 && newY
< WBOTTOM(data
->bottomList
[data
->bottomIndex
-1])) {
674 } else if (data
->topIndex
<= data
->count
-1
675 && newY2
<= WTOP(data
->topList
[data
->topIndex
])) {
678 } else if (newY
> data
->realY
) {
679 if (data
->topIndex
> 0
680 && newY2
> WTOP(data
->topList
[data
->topIndex
-1])) {
682 } else if (data
->bottomIndex
<= data
->count
-1
683 && newY
>= WBOTTOM(data
->bottomList
[data
->bottomIndex
])) {
692 /* TODO: optimize this */
693 if (data
->realY
< WBOTTOM(data
->bottomList
[0])) {
694 data
->bottomIndex
= 0;
696 if (data
->realX
< WRIGHT(data
->rightList
[0])) {
697 data
->rightIndex
= 0;
699 if ((data
->realX
+ data
->winWidth
) > WLEFT(data
->leftList
[0])) {
702 if ((data
->realY
+ data
->winHeight
) > WTOP(data
->topList
[0])) {
705 for (i
= 0; i
< data
->count
; i
++) {
706 if (data
->realY
> WBOTTOM(data
->bottomList
[i
])) {
707 data
->bottomIndex
= i
+ 1;
709 if (data
->realX
> WRIGHT(data
->rightList
[i
])) {
710 data
->rightIndex
= i
+ 1;
712 if ((data
->realX
+ data
->winWidth
) < WLEFT(data
->leftList
[i
])) {
713 data
->leftIndex
= i
+ 1;
715 if ((data
->realY
+ data
->winHeight
) < WTOP(data
->topList
[i
])) {
716 data
->topIndex
= i
+ 1;
723 freeMoveData(MoveData
*data
)
728 free(data
->leftList
);
730 free(data
->rightList
);
731 if (data
->bottomList
)
732 free(data
->bottomList
);
737 updateMoveData(WWindow
*wwin
, MoveData
*data
)
739 WScreen
*scr
= wwin
->screen_ptr
;
744 tmp
= scr
->focused_window
;
746 if (tmp
!= wwin
&& scr
->current_workspace
== tmp
->frame
->workspace
747 && !tmp
->flags
.miniaturized
748 && !tmp
->flags
.hidden
749 && !tmp
->flags
.obscured
750 && !WFLAGP(tmp
, sunken
)) {
751 data
->topList
[data
->count
] = tmp
;
752 data
->leftList
[data
->count
] = tmp
;
753 data
->rightList
[data
->count
] = tmp
;
754 data
->bottomList
[data
->count
] = tmp
;
760 if (data
->count
== 0) {
763 data
->rightIndex
= 0;
764 data
->bottomIndex
= 0;
769 * order from closest to the border of the screen to farthest
771 qsort(data
->topList
, data
->count
, sizeof(WWindow
**), compareWTop
);
772 qsort(data
->leftList
, data
->count
, sizeof(WWindow
**), compareWLeft
);
773 qsort(data
->rightList
, data
->count
, sizeof(WWindow
**), compareWRight
);
774 qsort(data
->bottomList
, data
->count
, sizeof(WWindow
**), compareWBottom
);
776 /* figure the position of the window relative to the others */
779 data
->leftIndex
= -1;
780 data
->rightIndex
= -1;
781 data
->bottomIndex
= -1;
783 if (WTOP(wwin
) < WBOTTOM(data
->bottomList
[0])) {
784 data
->bottomIndex
= 0;
786 if (WLEFT(wwin
) < WRIGHT(data
->rightList
[0])) {
787 data
->rightIndex
= 0;
789 if (WRIGHT(wwin
) > WLEFT(data
->leftList
[0])) {
792 if (WBOTTOM(wwin
) > WTOP(data
->topList
[0])) {
795 for (i
= 0; i
< data
->count
; i
++) {
796 if (WTOP(wwin
) >= WBOTTOM(data
->bottomList
[i
])) {
797 data
->bottomIndex
= i
+ 1;
799 if (WLEFT(wwin
) >= WRIGHT(data
->rightList
[i
])) {
800 data
->rightIndex
= i
+ 1;
802 if (WRIGHT(wwin
) <= WLEFT(data
->leftList
[i
])) {
803 data
->leftIndex
= i
+ 1;
805 if (WBOTTOM(wwin
) <= WTOP(data
->topList
[i
])) {
806 data
->topIndex
= i
+ 1;
813 initMoveData(WWindow
*wwin
, MoveData
*data
)
818 memset(data
, 0, sizeof(MoveData
));
820 for (i
= 0, tmp
= wwin
->screen_ptr
->focused_window
;
822 tmp
= tmp
->prev
, i
++);
825 data
->topList
= wmalloc(sizeof(WWindow
*) * i
);
826 data
->leftList
= wmalloc(sizeof(WWindow
*) * i
);
827 data
->rightList
= wmalloc(sizeof(WWindow
*) * i
);
828 data
->bottomList
= wmalloc(sizeof(WWindow
*) * i
);
830 updateMoveData(wwin
, data
);
833 data
->realX
= wwin
->frame_x
;
834 data
->realY
= wwin
->frame_y
;
835 data
->calcX
= wwin
->frame_x
;
836 data
->calcY
= wwin
->frame_y
;
838 data
->winWidth
= wwin
->frame
->core
->width
+ 2;
839 data
->winHeight
= wwin
->frame
->core
->height
+ 2;
844 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,
857 } else if (scr
->current_workspace
== 0 && wPreferences
.ws_cycle
) {
859 crossWorkspace(scr
, wwin
, opaqueMove
, scr
->workspace_count
- 1,
864 } else if (data
->mouseX
>= scr
->scr_width
- 2) {
866 if (scr
->current_workspace
== scr
->workspace_count
- 1) {
868 if (wPreferences
.ws_cycle
869 || scr
->workspace_count
== MAX_WORKSPACES
) {
871 crossWorkspace(scr
, wwin
, opaqueMove
, 0, False
);
875 /* if user insists on trying to go to next workspace even when
876 * it's already the last, create a new one */
877 else if (data
->omouseX
== data
->mouseX
878 && wPreferences
.ws_advance
) {
880 /* detect user "rubbing" the window against the edge */
881 if (data
->rubCount
> 0
882 && data
->omouseY
- data
->mouseY
> MOVE_THRESHOLD
) {
884 data
->rubCount
= -(data
->rubCount
+ 1);
886 } else if (data
->rubCount
<= 0
887 && data
->mouseY
- data
->omouseY
> MOVE_THRESHOLD
) {
889 data
->rubCount
= -data
->rubCount
+ 1;
892 /* create a new workspace */
893 if (abs(data
->rubCount
) > 2) {
894 /* go to next workspace */
897 crossWorkspace(scr
, wwin
, opaqueMove
,
898 scr
->current_workspace
+1, False
);
902 } else if (scr
->current_workspace
< scr
->workspace_count
) {
904 /* go to next workspace */
905 crossWorkspace(scr
, wwin
, opaqueMove
,
906 scr
->current_workspace
+1, False
);
919 updateWindowPosition(WWindow
*wwin
, MoveData
*data
, Bool doResistance
,
920 Bool opaqueMove
, int newMouseX
, int newMouseY
)
922 WScreen
*scr
= wwin
->screen_ptr
;
923 int dx
, dy
; /* how much mouse moved */
924 int winL
, winR
, winT
, winB
; /* requested new window position */
925 int newX
, newY
; /* actual new window position */
926 Bool hresist
, vresist
;
935 /* check the direction of the movement */
936 dx
= newMouseX
- data
->mouseX
;
937 dy
= newMouseY
- data
->mouseY
;
939 data
->omouseX
= data
->mouseX
;
940 data
->omouseY
= data
->mouseY
;
941 data
->mouseX
= newMouseX
;
942 data
->mouseY
= newMouseY
;
944 winL
= data
->calcX
+ dx
;
945 winR
= data
->calcX
+ data
->winWidth
+ dx
;
946 winT
= data
->calcY
+ dy
;
947 winB
= data
->calcY
+ data
->winHeight
+ dy
;
959 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
960 attract
= wPreferences
.attract
;
961 /* horizontal movement: check horizontal edge resistances */
964 /* window is the leftmost window: check against screen edge */
965 l_edge
= scr
->totalUsableArea
.x1
;
966 r_edge
= scr
->totalUsableArea
.x2
+ resist
;
967 edge_l
= scr
->totalUsableArea
.x1
- resist
;
968 edge_r
= scr
->totalUsableArea
.x2
;
971 if ((data
->rightIndex
>= 0) && (data
->rightIndex
<= data
->count
)) {
974 for (i
= data
->rightIndex
- 1; i
>= 0; i
--) {
975 looprw
= data
->rightList
[i
];
976 if (!(data
->realY
> WBOTTOM(looprw
)
977 || (data
->realY
+ data
->winHeight
) < WTOP(looprw
))) {
979 || ((data
->realX
< (WRIGHT(looprw
) + 2)) && dx
< 0)) {
980 l_edge
= WRIGHT(looprw
) + 1;
981 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
988 for (i
= data
->rightIndex
; i
< data
->count
; i
++) {
989 looprw
= data
->rightList
[i
];
990 if(!(data
->realY
> WBOTTOM(looprw
)
991 || (data
->realY
+ data
->winHeight
) < WTOP(looprw
))) {
992 r_edge
= WRIGHT(looprw
) + 1;
993 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
1000 if ((data
->leftIndex
>= 0) && (data
->leftIndex
<= data
->count
)) {
1003 for (i
= data
->leftIndex
- 1; i
>= 0; i
--) {
1004 looprw
= data
->leftList
[i
];
1005 if (!(data
->realY
> WBOTTOM(looprw
)
1006 || (data
->realY
+ data
->winHeight
) < WTOP(looprw
))) {
1008 || (((data
->realX
+ data
->winWidth
) > (WLEFT(looprw
) - 1)) && dx
> 0)) {
1009 edge_r
= WLEFT(looprw
);
1010 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
1017 for (i
= data
->leftIndex
; i
< data
->count
; i
++) {
1018 looprw
= data
->leftList
[i
];
1019 if(!(data
->realY
> WBOTTOM(looprw
)
1020 || (data
->realY
+ data
->winHeight
) < WTOP(looprw
))) {
1021 edge_l
= WLEFT(looprw
);
1022 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
1029 printf("%d %d\n",winL,winR);
1030 printf("l_ %d r_ %d _l %d _r %d\n",l_edge,r_edge,edge_l,edge_r);
1033 if ((winL
- l_edge
) < (r_edge
- winL
)) {
1035 if ((attract
&& winL
<= l_edge
+ resist
&& winL
>= l_edge
- resist
)
1036 || (dx
< 0 && winL
<= l_edge
&& winL
>= l_edge
- resist
)) {
1042 if (resist
> 0 && attract
&& winL
>= r_edge
- resist
&& winL
<= r_edge
+ resist
) {
1048 if ((winR
- edge_l
) < (edge_r
- winR
)) {
1049 if (resist
> 0 && attract
&& winR
<= edge_l
+ resist
&& winR
>= edge_l
- resist
) {
1050 newX
= edge_l
- data
->winWidth
;
1055 if ((attract
&& winR
>= edge_r
- resist
&& winR
<= edge_r
+ resist
)
1056 || (dx
> 0 && winR
>= edge_r
&& winR
<= edge_r
+ resist
)) {
1057 newX
= edge_r
- data
->winWidth
;
1064 t_edge
= scr
->totalUsableArea
.y1
;
1065 b_edge
= scr
->totalUsableArea
.y2
+ resist
;
1066 edge_t
= scr
->totalUsableArea
.y1
- resist
;
1067 edge_b
= scr
->totalUsableArea
.y2
;
1069 if ((data
->bottomIndex
>= 0) && (data
->bottomIndex
<= data
->count
)) {
1072 for (i
= data
->bottomIndex
- 1; i
>= 0; i
--) {
1073 looprw
= data
->bottomList
[i
];
1074 if (!(data
->realX
> WRIGHT(looprw
)
1075 || (data
->realX
+ data
->winWidth
) < WLEFT(looprw
))) {
1077 || ((data
->realY
< (WBOTTOM(looprw
) + 2)) && dy
< 0)) {
1078 t_edge
= WBOTTOM(looprw
) + 1;
1079 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
1086 for (i
= data
->bottomIndex
; i
< data
->count
; i
++) {
1087 looprw
= data
->bottomList
[i
];
1088 if(!(data
->realX
> WRIGHT(looprw
)
1089 || (data
->realX
+ data
->winWidth
) < WLEFT(looprw
))) {
1090 b_edge
= WBOTTOM(looprw
) + 1;
1091 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
1098 if ((data
->topIndex
>= 0) && (data
->topIndex
<= data
->count
)) {
1101 for (i
= data
->topIndex
- 1; i
>= 0; i
--) {
1102 looprw
= data
->topList
[i
];
1103 if (!(data
->realX
> WRIGHT(looprw
)
1104 || (data
->realX
+ data
->winWidth
) < WLEFT(looprw
))) {
1106 || (((data
->realY
+ data
->winHeight
) > (WTOP(looprw
) - 1)) && dy
> 0)) {
1107 edge_b
= WTOP(looprw
);
1108 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
1115 for (i
= data
->topIndex
; i
< data
->count
; i
++) {
1116 looprw
= data
->topList
[i
];
1117 if(!(data
->realX
> WRIGHT(looprw
)
1118 || (data
->realX
+ data
->winWidth
) < WLEFT(looprw
))) {
1119 edge_t
= WTOP(looprw
);
1120 resist
= WIN_RESISTANCE(wPreferences
.edge_resistance
);
1126 if ((winT
- t_edge
) < (b_edge
- winT
)) {
1128 if ((attract
&& winT
<= t_edge
+ resist
&& winT
>= t_edge
- resist
)
1129 || (dy
< 0 && winT
<= t_edge
&& winT
>= t_edge
- resist
)) {
1136 if (resist
> 0 && attract
&& winT
>= b_edge
- resist
&& winT
<= b_edge
+ resist
) {
1142 if ((winB
- edge_t
) < (edge_b
- winB
)) {
1143 if (resist
> 0 && attract
&& winB
<= edge_t
+ resist
&& winB
>= edge_t
- resist
) {
1144 newY
= edge_t
- data
->winHeight
;
1150 if ((attract
&& winB
>= edge_b
- resist
&& winB
<= edge_b
+ resist
)
1151 || (dy
> 0 && winB
>= edge_b
&& winB
<= edge_b
+ resist
)) {
1152 newY
= edge_b
- data
->winHeight
;
1162 /* update window position */
1166 if (((dx
> 0 && data
->calcX
- data
->realX
> 0)
1167 || (dx
< 0 && data
->calcX
- data
->realX
< 0)) && !hresist
)
1170 if (((dy
> 0 && data
->calcY
- data
->realY
> 0)
1171 || (dy
< 0 && data
->calcY
- data
->realY
< 0)) && !vresist
)
1174 if (data
->realX
!= newX
|| data
->realY
!= newY
) {
1176 if (wPreferences
.move_display
== WDIS_NEW
1177 && !scr
->selected_windows
) {
1178 showPosition(wwin
, data
->realX
, data
->realY
);
1181 doWindowMove(wwin
, scr
->selected_windows
,
1182 newX
- wwin
->frame_x
,
1183 newY
- wwin
->frame_y
);
1186 drawFrames(wwin
, scr
->selected_windows
,
1187 data
->realX
- wwin
->frame_x
,
1188 data
->realY
- wwin
->frame_y
);
1191 if (!scr
->selected_windows
1192 && wPreferences
.move_display
== WDIS_FRAME_CENTER
) {
1194 moveGeometryDisplayCentered(scr
, newX
+ data
->winWidth
/2,
1195 newY
+ data
->winHeight
/2);
1200 drawFrames(wwin
, scr
->selected_windows
,
1201 newX
- wwin
->frame_x
,
1202 newY
- wwin
->frame_y
);
1205 if (!scr
->selected_windows
) {
1206 showPosition(wwin
, newX
, newY
);
1211 /* recalc relative window position */
1212 if (doResistance
&& (data
->realX
!= newX
|| data
->realY
!= newY
)) {
1213 updateResistance(wwin
, data
, newX
, newY
);
1221 #define _KS KEY_CONTROL_WINDOW_WEIGHT
1224 wKeyboardMoveResizeWindow(WWindow
*wwin
)
1226 WScreen
*scr
= wwin
->screen_ptr
;
1227 Window root
= scr
->root_win
;
1229 int w
= wwin
->frame
->core
->width
;
1230 int h
= wwin
->frame
->core
->height
;
1231 int scr_width
= wwin
->screen_ptr
->scr_width
;
1232 int scr_height
= wwin
->screen_ptr
->scr_height
;
1233 int vert_border
= wwin
->frame
->top_width
+ wwin
->frame
->bottom_width
;
1234 int src_x
= wwin
->frame_x
;
1235 int src_y
= wwin
->frame_y
;
1236 int done
,off_x
,off_y
,ww
,wh
;
1239 KeySym keysym
=NoSymbol
;
1241 KeyCode shiftl
,shiftr
,ctrll
,ctrlmode
;
1243 shiftl
= XKeysymToKeycode(dpy
, XK_Shift_L
);
1244 shiftr
= XKeysymToKeycode(dpy
, XK_Shift_R
);
1245 ctrll
= XKeysymToKeycode(dpy
, XK_Control_L
);
1246 ctrlmode
=done
=off_x
=off_y
=0;
1250 XGrabKeyboard(dpy
, root
, False
, GrabModeAsync
, GrabModeAsync
, CurrentTime
);
1252 if (!wwin
->flags
.selected
) {
1253 wUnselectWindows(scr
);
1256 XGrabPointer(dpy
, scr
->root_win
, True
, PointerMotionMask
1257 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
1258 GrabModeAsync
, None
, wCursor
[WCUR_DEFAULT
], CurrentTime
);
1260 if (wwin
->flags
.shaded
|| scr
->selected_windows
) {
1261 if(scr
->selected_windows
)
1262 drawFrames(wwin
,scr
->selected_windows
,off_x
,off_y
);
1263 else drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, w
, h
);
1264 if(!scr
->selected_windows
)
1265 mapPositionDisplay(wwin
, src_x
, src_y
, w
, h
);
1267 drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, w
, h
);
1276 WMMaskEvent(dpy
, KeyPressMask
| ButtonReleaseMask
1277 | ButtonPressMask
| ExposureMask
, &event
);
1278 if (wwin
->flags
.shaded
|| scr
->selected_windows
) {
1279 if(scr
->selected_windows
)
1280 drawFrames(wwin
,scr
->selected_windows
,off_x
,off_y
);
1281 else drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, w
, h
);
1282 /*** I HATE EDGE RESISTANCE - ]d ***/
1285 drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, ww
, wh
);
1289 showGeometry(wwin
, src_x
+off_x
, src_y
+off_y
, src_x
+off_x
+ww
, src_y
+off_y
+wh
,0);
1294 switch (event
.type
) {
1297 if (event
.xkey
.time
- lastTime
> 50) {
1298 kspeed
/=(1 + (event
.xkey
.time
- lastTime
)/100);
1304 if (kspeed
< _KS
) kspeed
= _KS
;
1305 lastTime
= event
.xkey
.time
;
1307 if (event
.xkey
.state
& ControlMask
&& !wwin
->flags
.shaded
) {
1309 wUnselectWindows(scr
);
1314 if (event
.xkey
.keycode
== shiftl
|| event
.xkey
.keycode
== shiftr
) {
1316 cycleGeometryDisplay(wwin
, src_x
+off_x
, src_y
+off_y
, ww
, wh
, 0);
1318 cyclePositionDisplay(wwin
, src_x
+off_x
, src_y
+off_y
, ww
, wh
);
1322 keysym
= XLookupKeysym(&event
.xkey
, 0);
1369 if (moment
!= RIGHT
)
1380 wWindowConstrainSize(wwin
, &ww
, &wh
);
1383 if (wPreferences
.ws_cycle
){
1384 if (src_x
+ off_x
+ ww
< 20){
1385 if(!scr
->current_workspace
) {
1386 wWorkspaceChange(scr
, scr
->workspace_count
-1);
1388 else wWorkspaceChange(scr
, scr
->current_workspace
-1);
1391 else if (src_x
+ off_x
+ 20 > scr_width
){
1392 if(scr
->current_workspace
== scr
->workspace_count
-1) {
1393 wWorkspaceChange(scr
, 0);
1395 else wWorkspaceChange(scr
, scr
->current_workspace
+1);
1400 if (src_x
+ off_x
+ ww
< 20)
1401 off_x
= 20 - ww
- src_x
;
1402 else if (src_x
+ off_x
+ 20 > scr_width
)
1403 off_x
= scr_width
- 20 - src_x
;
1406 if (src_y
+ off_y
+ wh
< 20) {
1407 off_y
= 20 - wh
- src_y
;
1409 else if (src_y
+ off_y
+ 20 > scr_height
) {
1410 off_y
= scr_height
- 20 - src_y
;
1419 WMHandleEvent(&event
);
1426 if (wwin
->flags
.shaded
&& !scr
->selected_windows
){
1427 moveGeometryDisplayCentered(scr
, src_x
+off_x
+ w
/2, src_y
+off_y
+ h
/2);
1431 unmapPositionDisplay(wwin
);
1432 mapGeometryDisplay(wwin
, src_x
+off_x
, src_y
+off_y
, ww
, wh
);
1434 else if(!scr
->selected_windows
){
1435 unmapGeometryDisplay(wwin
);
1436 mapPositionDisplay(wwin
, src_x
+off_x
, src_y
+off_y
, ww
, wh
);
1440 if (wwin
->flags
.shaded
|| scr
->selected_windows
) {
1441 if(scr
->selected_windows
)
1442 drawFrames(wwin
,scr
->selected_windows
,off_x
,off_y
);
1443 else drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, w
, h
);
1446 drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, ww
, wh
);
1451 showGeometry(wwin
, src_x
+off_x
, src_y
+off_y
, src_x
+off_x
+ww
, src_y
+off_y
+wh
,0);
1453 else if(!scr
->selected_windows
)
1454 showPosition(wwin
, src_x
+off_x
, src_y
+off_y
);
1458 scr
->keymove_tick
=0;
1460 WMDeleteTimerWithClientData(&looper);
1462 if (wwin
->flags
.shaded
|| scr
->selected_windows
) {
1463 if(scr
->selected_windows
)
1464 drawFrames(wwin
,scr
->selected_windows
,off_x
,off_y
);
1465 else drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, w
, h
);
1468 drawTransparentFrame(wwin
, src_x
+off_x
, src_y
+off_y
, ww
, wh
);
1472 showGeometry(wwin
, src_x
+off_x
, src_y
+off_y
, src_x
+off_x
+ww
, src_y
+off_y
+wh
,0);
1473 unmapGeometryDisplay(wwin
);
1476 unmapPositionDisplay(wwin
);
1477 XUngrabKeyboard(dpy
, CurrentTime
);
1478 XUngrabPointer(dpy
, CurrentTime
);
1482 if (wwin
->flags
.shaded
|| scr
->selected_windows
) {
1483 if (!scr
->selected_windows
) {
1484 wWindowMove(wwin
, src_x
+off_x
, src_y
+off_y
);
1485 wWindowSynthConfigureNotify(wwin
);
1488 WMBag
*bag
= scr
->selected_windows
;
1489 doWindowMove(wwin
,scr
->selected_windows
,off_x
,off_y
);
1490 for (i
= 0; i
< WMGetBagItemCount(bag
); i
++) {
1491 wWindowSynthConfigureNotify(WMGetFromBag(bag
, i
));
1495 if (wwin
->client
.width
!= ww
)
1496 wwin
->flags
.user_changed_width
= 1;
1498 if (wwin
->client
.height
!= wh
- vert_border
)
1499 wwin
->flags
.user_changed_height
= 1;
1501 wWindowConfigure(wwin
, src_x
+off_x
, src_y
+off_y
,
1502 ww
, wh
- vert_border
);
1503 wWindowSynthConfigureNotify(wwin
);
1505 wWindowChangeWorkspace(wwin
, scr
->current_workspace
);
1506 wSetFocusTo(scr
, wwin
);
1515 *----------------------------------------------------------------------
1516 * wMouseMoveWindow--
1517 * Move the named window and the other selected ones (if any),
1518 * interactively. Also shows the position of the window, if only one
1519 * window is being moved.
1520 * If the window is not on the selected window list, the selected
1521 * windows are deselected.
1522 * If shift is pressed during the operation, the position display
1523 * is changed to another type.
1526 * True if the window was moved, False otherwise.
1529 * The window(s) position is changed, and the client(s) are
1530 * notified about that.
1531 * The position display configuration may be changed.
1532 *----------------------------------------------------------------------
1535 wMouseMoveWindow(WWindow
*wwin
, XEvent
*ev
)
1537 WScreen
*scr
= wwin
->screen_ptr
;
1539 Window root
= scr
->root_win
;
1540 KeyCode shiftl
, shiftr
;
1544 /* This needs not to change while moving, else bad things can happen */
1545 int opaqueMove
= wPreferences
.opaque_move
;
1547 #ifdef GHOST_WINDOW_MOVE
1550 rimg
= InitGhostWindowMove(scr
);
1554 if (wPreferences
.opaque_move
&& !wPreferences
.use_saveunders
) {
1555 XSetWindowAttributes attr
;
1557 attr
.save_under
= True
;
1558 XChangeWindowAttributes(dpy
, wwin
->frame
->core
->window
,
1559 CWSaveUnder
, &attr
);
1563 initMoveData(wwin
, &moveData
);
1565 moveData
.mouseX
= ev
->xmotion
.x_root
;
1566 moveData
.mouseY
= ev
->xmotion
.y_root
;
1568 if (!wwin
->flags
.selected
) {
1569 /* this window is not selected, unselect others and move only wwin */
1570 wUnselectWindows(scr
);
1573 puts("Moving window");
1575 shiftl
= XKeysymToKeycode(dpy
, XK_Shift_L
);
1576 shiftr
= XKeysymToKeycode(dpy
, XK_Shift_R
);
1582 /* XWarpPointer() doesn't seem to generate Motion events, so
1583 we've got to simulate them */
1584 XQueryPointer(dpy
, root
, &junkw
, &junkw
, &event
.xmotion
.x_root
,
1585 &event
.xmotion
.y_root
, &junk
, &junk
,
1586 (unsigned *) &junk
);
1588 WMMaskEvent(dpy
, KeyPressMask
| ButtonMotionMask
1589 | ButtonReleaseMask
| ButtonPressMask
| ExposureMask
,
1592 if (event
.type
== MotionNotify
) {
1593 /* compress MotionNotify events */
1594 while (XCheckMaskEvent(dpy
, ButtonMotionMask
, &event
)) ;
1597 switch (event
.type
) {
1599 if ((event
.xkey
.keycode
== shiftl
|| event
.xkey
.keycode
== shiftr
)
1600 && started
&& !scr
->selected_windows
) {
1603 drawFrames(wwin
, scr
->selected_windows
,
1604 moveData
.realX
- wwin
->frame_x
,
1605 moveData
.realY
- wwin
->frame_y
);
1608 if (wPreferences
.move_display
== WDIS_NEW
1609 && !scr
->selected_windows
) {
1610 showPosition(wwin
, moveData
.realX
, moveData
.realY
);
1613 cyclePositionDisplay(wwin
, moveData
.realX
, moveData
.realY
,
1614 moveData
.winWidth
, moveData
.winHeight
);
1616 if (wPreferences
.move_display
== WDIS_NEW
1617 && !scr
->selected_windows
) {
1619 showPosition(wwin
, moveData
.realX
, moveData
.realY
);
1623 drawFrames(wwin
, scr
->selected_windows
,
1624 moveData
.realX
- wwin
->frame_x
,
1625 moveData
.realY
- wwin
->frame_y
);
1632 updateWindowPosition(wwin
, &moveData
,
1633 scr
->selected_windows
== NULL
1634 && wPreferences
.edge_resistance
> 0,
1636 event
.xmotion
.x_root
,
1637 event
.xmotion
.y_root
);
1639 if (!warped
&& !wPreferences
.no_autowrap
) {
1640 int oldWorkspace
= scr
->current_workspace
;
1642 if (wPreferences
.move_display
== WDIS_NEW
1643 && !scr
->selected_windows
) {
1644 showPosition(wwin
, moveData
.realX
, moveData
.realY
);
1648 drawFrames(wwin
, scr
->selected_windows
,
1649 moveData
.realX
- wwin
->frame_x
,
1650 moveData
.realY
- wwin
->frame_y
);
1652 if (checkWorkspaceChange(wwin
, &moveData
, opaqueMove
)) {
1653 if (scr
->current_workspace
!= oldWorkspace
1654 && wPreferences
.edge_resistance
> 0
1655 && scr
->selected_windows
== NULL
)
1656 updateMoveData(wwin
, &moveData
);
1660 drawFrames(wwin
, scr
->selected_windows
,
1661 moveData
.realX
- wwin
->frame_x
,
1662 moveData
.realY
- wwin
->frame_y
);
1664 if (wPreferences
.move_display
== WDIS_NEW
1665 && !scr
->selected_windows
) {
1667 showPosition(wwin
, moveData
.realX
, moveData
.realY
);
1673 } else if (abs(ev
->xmotion
.x_root
- event
.xmotion
.x_root
) >= MOVE_THRESHOLD
1674 || abs(ev
->xmotion
.y_root
- event
.xmotion
.y_root
) >= MOVE_THRESHOLD
) {
1676 XChangeActivePointerGrab(dpy
, ButtonMotionMask
1677 | ButtonReleaseMask
| ButtonPressMask
,
1678 wCursor
[WCUR_MOVE
], CurrentTime
);
1680 XGrabKeyboard(dpy
, root
, False
, GrabModeAsync
, GrabModeAsync
,
1683 if (!scr
->selected_windows
)
1684 mapPositionDisplay(wwin
, moveData
.realX
, moveData
.realY
,
1685 moveData
.winWidth
, moveData
.winHeight
);
1687 if (started
&& !opaqueMove
)
1688 drawFrames(wwin
, scr
->selected_windows
, 0, 0);
1690 if (!opaqueMove
|| (wPreferences
.move_display
==WDIS_NEW
1691 && !scr
->selected_windows
)) {
1693 if (wPreferences
.move_display
==WDIS_NEW
)
1694 showPosition(wwin
, moveData
.realX
, moveData
.realY
);
1703 if (event
.xbutton
.button
!= ev
->xbutton
.button
)
1708 drawFrames(wwin
, scr
->selected_windows
,
1709 moveData
.realX
- wwin
->frame_x
,
1710 moveData
.realY
- wwin
->frame_y
);
1712 doWindowMove(wwin
, scr
->selected_windows
,
1713 moveData
.realX
- wwin
->frame_x
,
1714 moveData
.realY
- wwin
->frame_y
);
1716 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
1717 wWindowSynthConfigureNotify(wwin
);
1719 XUngrabKeyboard(dpy
, CurrentTime
);
1722 wWindowChangeWorkspace(wwin
, scr
->current_workspace
);
1723 wSetFocusTo(scr
, wwin
);
1725 if (wPreferences
.move_display
== WDIS_NEW
)
1726 showPosition(wwin
, moveData
.realX
, moveData
.realY
);
1728 if (!scr
->selected_windows
) {
1729 /* get rid of the geometry window */
1730 unmapPositionDisplay(wwin
);
1734 puts("End move window");
1740 if (started
&& !opaqueMove
) {
1741 drawFrames(wwin
, scr
->selected_windows
,
1742 moveData
.realX
- wwin
->frame_x
,
1743 moveData
.realY
- wwin
->frame_y
);
1745 WMHandleEvent(&event
);
1748 drawFrames(wwin
, scr
->selected_windows
,
1749 moveData
.realX
- wwin
->frame_x
,
1750 moveData
.realY
- wwin
->frame_y
);
1752 WMHandleEvent(&event
);
1758 if (wPreferences
.opaque_move
&& !wPreferences
.use_saveunders
) {
1759 XSetWindowAttributes attr
;
1762 attr
.save_under
= False
;
1763 XChangeWindowAttributes(dpy
, wwin
->frame
->core
->window
,
1764 CWSaveUnder
, &attr
);
1768 freeMoveData(&moveData
);
1775 #define HCONSTRAIN 2
1778 getResizeDirection(WWindow
*wwin
, int x
, int y
, int dx
, int dy
,
1781 int w
= wwin
->frame
->core
->width
- 1;
1782 int cw
= wwin
->frame
->resizebar_corner_width
;
1785 /* if not resizing through the resizebar */
1786 if (!(flags
& RESIZEBAR
)) {
1787 int xdir
= (abs(x
) < (wwin
->client
.width
/2)) ? LEFT
: RIGHT
;
1788 int ydir
= (abs(y
) < (wwin
->client
.height
/2)) ? UP
: DOWN
;
1789 if (abs(dx
) < 2 || abs(dy
) < 2) {
1790 if (abs(dy
) > abs(dx
))
1795 return (xdir
| ydir
);
1798 /* window is too narrow. allow diagonal resize */
1802 if (flags
& HCONSTRAIN
)
1807 return (LEFT
| ydir
);
1809 return (RIGHT
| ydir
);
1811 /* vertical resize */
1812 if ((x
> cw
) && (x
< w
- cw
))
1820 if ((abs(dy
) > 0) && !(flags
& HCONSTRAIN
))
1828 wMouseResizeWindow(WWindow
*wwin
, XEvent
*ev
)
1831 WScreen
*scr
= wwin
->screen_ptr
;
1832 Window root
= scr
->root_win
;
1833 int vert_border
= wwin
->frame
->top_width
+ wwin
->frame
->bottom_width
;
1834 int fw
= wwin
->frame
->core
->width
;
1835 int fh
= wwin
->frame
->core
->height
;
1836 int fx
= wwin
->frame_x
;
1837 int fy
= wwin
->frame_y
;
1838 int is_resizebar
= (wwin
->frame
->resizebar
1839 && ev
->xany
.window
==wwin
->frame
->resizebar
->window
);
1843 int rw
= fw
, rh
= fh
;
1844 int rx1
, ry1
, rx2
, ry2
;
1846 KeyCode shiftl
, shiftr
;
1853 if (wwin
->flags
.shaded
) {
1854 wwarning("internal error: tryein");
1857 orig_x
= ev
->xbutton
.x_root
;
1858 orig_y
= ev
->xbutton
.y_root
;
1862 puts("Resizing window");
1865 wUnselectWindows(scr
);
1870 shiftl
= XKeysymToKeycode(dpy
, XK_Shift_L
);
1871 shiftr
= XKeysymToKeycode(dpy
, XK_Shift_R
);
1872 if (!WFLAGP(wwin
, no_titlebar
))
1873 h
= WMFontHeight(wwin
->screen_ptr
->title_font
) + TITLEBAR_EXTRA_HEIGHT
;
1877 WMMaskEvent(dpy
, KeyPressMask
| ButtonMotionMask
| ButtonReleaseMask
1878 | ButtonPressMask
| ExposureMask
, &event
);
1879 switch (event
.type
) {
1881 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
1882 if ((event
.xkey
.keycode
== shiftl
|| event
.xkey
.keycode
== shiftr
)
1884 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1885 cycleGeometryDisplay(wwin
, fx
, fy
, fw
, fh
, res
);
1886 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1888 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
1902 dw
= orig_x
- event
.xmotion
.x_root
;
1903 else if (res
& RIGHT
)
1904 dw
= event
.xmotion
.x_root
- orig_x
;
1906 dh
= orig_y
- event
.xmotion
.y_root
;
1907 else if (res
& DOWN
)
1908 dh
= event
.xmotion
.y_root
- orig_y
;
1910 orig_x
= event
.xmotion
.x_root
;
1911 orig_y
= event
.xmotion
.y_root
;
1916 fh
= rh
- vert_border
;
1917 wWindowConstrainSize(wwin
, &fw
, &fh
);
1921 else if (res
& RIGHT
)
1925 else if (res
& DOWN
)
1927 } else if (abs(orig_x
- event
.xmotion
.x_root
) >= MOVE_THRESHOLD
1928 || abs(orig_y
- event
.xmotion
.y_root
) >= MOVE_THRESHOLD
) {
1933 XTranslateCoordinates(dpy
, root
, wwin
->frame
->core
->window
,
1934 orig_x
, orig_y
, &tx
, &ty
, &junkw
);
1936 /* check if resizing through resizebar */
1942 if (is_resizebar
&& ((ev
->xbutton
.state
& ShiftMask
)
1943 || abs(orig_y
- event
.xmotion
.y_root
) < HRESIZE_THRESHOLD
))
1944 flags
|= HCONSTRAIN
;
1946 res
= getResizeDirection(wwin
, tx
, ty
,
1947 orig_x
- event
.xmotion
.x_root
,
1948 orig_y
- event
.xmotion
.y_root
, flags
);
1950 XChangeActivePointerGrab(dpy
, ButtonMotionMask
1951 | ButtonReleaseMask
| ButtonPressMask
,
1952 wCursor
[WCUR_RESIZE
], CurrentTime
);
1953 XGrabKeyboard(dpy
, root
, False
, GrabModeAsync
, GrabModeAsync
,
1958 /* Draw the resize frame for the first time. */
1959 mapGeometryDisplay(wwin
, fx
, fy
, fw
, fh
);
1961 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1963 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
1968 if (wPreferences
.size_display
== WDIS_FRAME_CENTER
) {
1969 drawTransparentFrame(wwin
, orig_fx
, orig_fy
,
1971 moveGeometryDisplayCentered(scr
, fx
+ fw
/ 2, fy
+ fh
/ 2);
1972 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1974 drawTransparentFrame(wwin
, orig_fx
, orig_fy
,
1976 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1978 if (fh
!= orig_fh
|| fw
!= orig_fw
) {
1979 if (wPreferences
.size_display
== WDIS_NEW
) {
1980 showGeometry(wwin
, orig_fx
, orig_fy
, orig_fx
+ orig_fw
,
1981 orig_fy
+ orig_fh
, res
);
1983 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
1992 if (event
.xbutton
.button
!= ev
->xbutton
.button
)
1996 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
1998 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
2000 XUngrabKeyboard(dpy
, CurrentTime
);
2001 unmapGeometryDisplay(wwin
);
2004 if (wwin
->client
.width
!= fw
)
2005 wwin
->flags
.user_changed_width
= 1;
2007 if (wwin
->client
.height
!= fh
- vert_border
)
2008 wwin
->flags
.user_changed_height
= 1;
2010 wWindowConfigure(wwin
, fx
, fy
, fw
, fh
- vert_border
);
2013 puts("End resize window");
2018 WMHandleEvent(&event
);
2033 wUnselectWindows(WScreen
*scr
)
2037 if (!scr
->selected_windows
)
2040 while (WMGetBagItemCount(scr
->selected_windows
)) {
2041 wwin
= WMGetFromBag(scr
->selected_windows
, 0);
2042 if (wwin
->flags
.miniaturized
&& wwin
->icon
&& wwin
->icon
->selected
)
2043 wIconSelect(wwin
->icon
);
2045 wSelectWindow(wwin
, False
);
2047 WMFreeBag(scr
->selected_windows
);
2048 scr
->selected_windows
= NULL
;
2053 selectWindowsInside(WScreen
*scr
, int x1
, int y1
, int x2
, int y2
)
2057 /* select the windows and put them in the selected window list */
2058 tmpw
= scr
->focused_window
;
2059 while (tmpw
!= NULL
) {
2060 if (!(tmpw
->flags
.miniaturized
|| tmpw
->flags
.hidden
)) {
2061 if ((tmpw
->frame
->workspace
== scr
->current_workspace
2062 || IS_OMNIPRESENT(tmpw
))
2063 && (tmpw
->frame_x
>= x1
) && (tmpw
->frame_y
>= y1
)
2064 && (tmpw
->frame
->core
->width
+ tmpw
->frame_x
<= x2
)
2065 && (tmpw
->frame
->core
->height
+ tmpw
->frame_y
<= y2
)) {
2066 wSelectWindow(tmpw
, True
);
2075 wSelectWindows(WScreen
*scr
, XEvent
*ev
)
2078 Window root
= scr
->root_win
;
2079 GC gc
= scr
->frame_gc
;
2080 int xp
= ev
->xbutton
.x_root
;
2081 int yp
= ev
->xbutton
.y_root
;
2086 puts("Selecting windows");
2088 if (XGrabPointer(dpy
, scr
->root_win
, False
, ButtonMotionMask
2089 | ButtonReleaseMask
| ButtonPressMask
, GrabModeAsync
,
2090 GrabModeAsync
, None
, wCursor
[WCUR_DEFAULT
],
2091 CurrentTime
) != Success
) {
2096 wUnselectWindows(scr
);
2098 XDrawRectangle(dpy
, root
, gc
, xp
, yp
, w
, h
);
2100 WMMaskEvent(dpy
, ButtonReleaseMask
| PointerMotionMask
2101 | ButtonPressMask
, &event
);
2103 switch (event
.type
) {
2105 XDrawRectangle(dpy
, root
, gc
, x
, y
, w
, h
);
2106 x
= event
.xmotion
.x_root
;
2113 y
= event
.xmotion
.y_root
;
2120 XDrawRectangle(dpy
, root
, gc
, x
, y
, w
, h
);
2127 if (event
.xbutton
.button
!= ev
->xbutton
.button
)
2130 XDrawRectangle(dpy
, root
, gc
, x
, y
, w
, h
);
2132 XUngrabPointer(dpy
, CurrentTime
);
2133 selectWindowsInside(scr
, x
, y
, x
+ w
, y
+ h
);
2136 wKWMSelectRootRegion(scr
, x
, y
, w
, h
,
2137 event
.xbutton
.state
& ControlMask
);
2138 #endif /* KWM_HINTS */
2141 puts("End window selection");
2146 WMHandleEvent(&event
);
2154 InteractivePlaceWindow(WWindow
*wwin
, int *x_ret
, int *y_ret
,
2155 unsigned width
, unsigned height
)
2157 WScreen
*scr
= wwin
->screen_ptr
;
2158 Window root
= scr
->root_win
;
2161 KeyCode shiftl
, shiftr
;
2165 if (XGrabPointer(dpy
, root
, True
, PointerMotionMask
| ButtonPressMask
,
2166 GrabModeAsync
, GrabModeAsync
, None
,
2167 wCursor
[WCUR_DEFAULT
], CurrentTime
) != Success
) {
2172 if (!WFLAGP(wwin
, no_titlebar
)) {
2173 h
= WMFontHeight(scr
->title_font
) + TITLEBAR_EXTRA_HEIGHT
;
2176 if (!WFLAGP(wwin
, no_resizebar
)) {
2177 height
+= RESIZEBAR_HEIGHT
;
2179 XGrabKeyboard(dpy
, root
, False
, GrabModeAsync
, GrabModeAsync
, CurrentTime
);
2180 XQueryPointer(dpy
, root
, &junkw
, &junkw
, &x
, &y
, &junk
, &junk
,
2181 (unsigned *) &junk
);
2182 mapPositionDisplay(wwin
, x
- width
/2, y
- h
/2, width
, height
);
2184 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
2186 shiftl
= XKeysymToKeycode(dpy
, XK_Shift_L
);
2187 shiftr
= XKeysymToKeycode(dpy
, XK_Shift_R
);
2189 WMMaskEvent(dpy
, PointerMotionMask
|ButtonPressMask
|ExposureMask
|KeyPressMask
,
2191 switch (event
.type
) {
2193 if ((event
.xkey
.keycode
== shiftl
)
2194 || (event
.xkey
.keycode
== shiftr
)) {
2195 drawTransparentFrame(wwin
,
2196 x
- width
/2, y
- h
/2, width
, height
);
2197 cyclePositionDisplay(wwin
,
2198 x
- width
/2, y
- h
/2, width
, height
);
2199 drawTransparentFrame(wwin
,
2200 x
- width
/2, y
- h
/2, width
, height
);
2205 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
2207 x
= event
.xmotion
.x_root
;
2208 y
= event
.xmotion
.y_root
;
2210 if (wPreferences
.move_display
== WDIS_FRAME_CENTER
)
2211 moveGeometryDisplayCentered(scr
, x
, y
+ (height
- h
) / 2);
2213 showPosition(wwin
, x
- width
/2, y
- h
/2);
2215 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
2220 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
2222 *x_ret
= x
- width
/2;
2224 XUngrabPointer(dpy
, CurrentTime
);
2225 XUngrabKeyboard(dpy
, CurrentTime
);
2226 /* get rid of the geometry window */
2227 unmapPositionDisplay(wwin
);
2231 WMHandleEvent(&event
);