2 * WindowMaker window manager
4 * Copyright (c) 1997, 1998 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>
30 #include "WindowMaker.h"
38 #include "workspace.h"
42 /* How many different types of geometry/position
43 display thingies are there? */
44 #define NUM_DISPLAYS 4
48 #define HORIZONTAL (LEFT|RIGHT)
51 #define VERTICAL (UP|DOWN)
53 /****** Global Variables ******/
54 extern Time LastTimestamp
;
56 extern Cursor wCursor
[WCUR_LAST
];
58 extern WPreferences wPreferences
;
60 extern Atom _XA_WM_PROTOCOLS
;
63 static LinkedList
*wSelectedWindows
=NULL
;
68 wGetGeometryWindowSize(WScreen
*scr
, unsigned int *width
,
72 *width
= XmbTextEscapement(scr
->info_text_font
->font
, "-8888 x -8888", 13);
73 *height
= (3 * scr
->info_text_font
->height
) / 2;
75 *width
= XTextWidth(scr
->info_text_font
->font
, "-8888 x -8888", 13);
76 *height
= (3 * scr
->info_text_font
->font
->ascent
) / 2;
82 *----------------------------------------------------------------------
83 * moveGeometryDisplayCentered
85 * routine that moves the geometry/position window on scr so it is
86 * centered over the given coordinates (x,y). Also the window position
87 * is clamped so it stays on the screen at all times.
88 *----------------------------------------------------------------------
91 moveGeometryDisplayCentered(WScreen
*scr
, int x
, int y
)
93 x
-= scr
->geometry_display_width
/ 2;
94 y
-= scr
->geometry_display_height
/ 2;
98 else if (x
> (scr
->scr_width
- scr
->geometry_display_width
- 3))
99 x
= scr
->scr_width
- scr
->geometry_display_width
- 3;
103 else if (y
> (scr
->scr_height
- scr
->geometry_display_height
- 3))
104 y
= scr
->scr_height
- scr
->geometry_display_height
- 3;
106 XMoveWindow(dpy
, scr
->geometry_display
, x
, y
);
111 showPosition(WWindow
*wwin
, int x
, int y
)
113 WScreen
*scr
= wwin
->screen_ptr
;
114 GC gc
= scr
->info_text_gc
;
118 if (wPreferences
.move_display
== WDIS_NEW
) {
120 int width
= wwin
->frame
->core
->width
;
121 int height
= wwin
->frame
->core
->height
;
123 GC lgc
= scr
->line_gc
;
124 XSetForeground(dpy
, lgc
, scr
->line_pixel
);
125 sprintf(num
, "%i", x
);
127 XDrawLine(dpy
, scr
->root_win
, lgc
, 0, y
-1, scr
->scr_width
, y
-1);
128 XDrawLine(dpy
, scr
->root_win
, lgc
, 0, y
+height
+2, scr
->scr_width
,
130 XDrawLine(dpy
, scr
->root_win
, lgc
, x
-1, 0, x
-1, scr
->scr_height
);
131 XDrawLine(dpy
, scr
->root_win
, lgc
, x
+width
+2, 0, x
+width
+2,
135 XClearWindow(dpy
, scr
->geometry_display
);
136 sprintf(num
, "%+i %-+i", x
, y
);
137 fw
= wTextWidth(scr
->info_text_font
->font
, num
, strlen(num
));
139 XSetForeground(dpy
, gc
, scr
->window_title_pixel
[WS_UNFOCUSED
]);
141 fh
= scr
->info_text_font
->height
;
142 wDrawString(scr
->geometry_display
, scr
->info_text_font
, gc
,
143 (scr
->geometry_display_width
- 2 - fw
) / 2,
144 (scr
->geometry_display_height
-fh
)/2 + scr
->info_text_font
->y
,
151 cyclePositionDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
)
153 WScreen
*scr
= wwin
->screen_ptr
;
155 wPreferences
.move_display
++;
156 wPreferences
.move_display
%= NUM_DISPLAYS
;
158 if (wPreferences
.move_display
== WDIS_NEW
) {
159 XUnmapWindow(dpy
, scr
->geometry_display
);
161 if (wPreferences
.move_display
== WDIS_CENTER
) {
162 moveGeometryDisplayCentered(scr
,
163 scr
->scr_width
/2, scr
->scr_height
/2);
164 } else if (wPreferences
.move_display
== WDIS_TOPLEFT
) {
165 moveGeometryDisplayCentered(scr
, 1, 1);
166 } else if (wPreferences
.move_display
== WDIS_FRAME_CENTER
) {
167 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
169 XMapRaised(dpy
, scr
->geometry_display
);
170 showPosition(wwin
, x
, y
);
176 mapPositionDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
)
178 WScreen
*scr
= wwin
->screen_ptr
;
180 if (wPreferences
.move_display
== WDIS_NEW
) {
182 } else if (wPreferences
.move_display
== WDIS_CENTER
) {
183 moveGeometryDisplayCentered(scr
, scr
->scr_width
/ 2,
184 scr
->scr_height
/ 2);
185 } else if (wPreferences
.move_display
== WDIS_TOPLEFT
) {
186 moveGeometryDisplayCentered(scr
, 1, 1);
187 } else if (wPreferences
.move_display
== WDIS_FRAME_CENTER
) {
188 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
190 XMapRaised(dpy
, scr
->geometry_display
);
191 showPosition(wwin
, x
, y
);
194 #define unmapPositionDisplay(w) \
195 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
199 showGeometry(WWindow
*wwin
, int x1
, int y1
, int x2
, int y2
, int direction
)
201 WScreen
*scr
= wwin
->screen_ptr
;
202 Window root
= scr
->root_win
;
203 GC gc
= scr
->line_gc
;
204 int ty
, by
, my
, x
, y
, mx
, s
;
209 ty
= y1
+ wwin
->frame
->top_width
;
210 by
= y2
- wwin
->frame
->bottom_width
;
211 fw
= wTextWidth(scr
->info_text_font
->font
, "8888", 4);
212 fh
= scr
->info_text_font
->height
;
214 if (wPreferences
.size_display
== WDIS_NEW
) {
215 XSetForeground(dpy
, gc
, scr
->line_pixel
);
217 /* vertical geometry */
218 if (((direction
& LEFT
) && (x2
< scr
->scr_width
- fw
)) || (x1
< fw
)) {
229 segment
[0].x1
= x
- (s
+ 6); segment
[0].y1
= ty
;
230 segment
[0].x2
= x
- (s
- 10); segment
[0].y2
= ty
;
233 segment
[1].x1
= x
- (s
- 2); segment
[1].y1
= ty
+ 1;
234 segment
[1].x2
= x
- (s
- 5); segment
[1].y2
= ty
+ 7;
236 segment
[2].x1
= x
- (s
- 2); segment
[2].y1
= ty
+ 1;
237 segment
[2].x2
= x
- (s
+ 1); segment
[2].y2
= ty
+ 7;
240 segment
[3].x1
= x
- (s
- 2); segment
[3].y1
= ty
+ 1;
241 segment
[3].x2
= x
- (s
- 2); segment
[3].y2
= my
- fh
/2 - 1;
243 XDrawSegments(dpy
, root
, gc
, segment
, 4);
251 segment
[1].y1
= by
- 1;
252 segment
[1].y2
= by
- 7;
254 segment
[2].y1
= by
- 1;
255 segment
[2].y2
= by
- 7;
258 segment
[3].y1
= my
+ fh
/2 + 2;
259 segment
[3].y2
= by
- 1;
261 XDrawSegments(dpy
, root
, gc
, segment
, 4);
263 sprintf(num
, "%i", (by
- ty
- wwin
->normal_hints
->base_height
) /
264 wwin
->normal_hints
->height_inc
);
265 fw
= wTextWidth(scr
->info_text_font
->font
, num
, strlen(num
));
267 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
269 /* Display the height. */
270 wDrawString(root
, scr
->info_text_font
, gc
,
271 x
- s
+ 3 - fw
/2, my
- fh
/2 + scr
->info_text_font
->y
+ 1,
273 XSetForeground(dpy
, gc
, scr
->line_pixel
);
274 /* horizontal geometry */
282 mx
= x1
+ (x2
- x1
)/2;
283 sprintf(num
, "%i", (x2
- x1
- wwin
->normal_hints
->base_width
) /
284 wwin
->normal_hints
->width_inc
);
285 fw
= wTextWidth(scr
->info_text_font
->font
, num
, strlen(num
));
289 segment
[0].x1
= x1
; segment
[0].y1
= y
- (s
+ 6);
290 segment
[0].x2
= x1
; segment
[0].y2
= y
- (s
- 10);
293 segment
[1].x1
= x1
+ 7; segment
[1].y1
= y
- (s
+ 1);
294 segment
[1].x2
= x1
+ 1; segment
[1].y2
= y
- (s
- 2);
296 segment
[2].x1
= x1
+ 1; segment
[2].y1
= y
- (s
- 2);
297 segment
[2].x2
= x1
+ 7; segment
[2].y2
= y
- (s
- 5);
300 segment
[3].x1
= x1
+ 1; segment
[3].y1
= y
- (s
- 2);
301 segment
[3].x2
= mx
- fw
/2 - 2; segment
[3].y2
= y
- (s
- 2);
303 XDrawSegments(dpy
, root
, gc
, segment
, 4);
307 segment
[0].x1
= x2
+ 1;
308 segment
[0].x2
= x2
+ 1;
311 segment
[1].x1
= x2
- 6;
315 segment
[2].x2
= x2
- 6;
318 segment
[3].x1
= mx
+ fw
/2 + 2;
321 XDrawSegments(dpy
, root
, gc
, segment
, 4);
323 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
325 /* Display the width. */
326 wDrawString(root
, scr
->info_text_font
, gc
,
327 mx
- fw
/2 + 1, y
- s
+ fh
/2 + 1, num
, strlen(num
));
329 XClearWindow(dpy
, scr
->geometry_display
);
330 sprintf(num
, "%i x %-i", (x2
- x1
- wwin
->normal_hints
->base_width
)
331 / wwin
->normal_hints
->width_inc
,
332 (by
- ty
- wwin
->normal_hints
->base_height
)
333 / wwin
->normal_hints
->height_inc
);
334 fw
= wTextWidth(scr
->info_text_font
->font
, num
, strlen(num
));
336 XSetForeground(dpy
, scr
->info_text_gc
,
337 scr
->window_title_pixel
[WS_UNFOCUSED
]);
339 /* Display the height. */
340 wDrawString(scr
->geometry_display
, scr
->info_text_font
,
342 (scr
->geometry_display_width
-fw
)/2,
343 (scr
->geometry_display_height
-fh
)/2 +scr
->info_text_font
->y
,
350 cycleGeometryDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
, int dir
)
352 WScreen
*scr
= wwin
->screen_ptr
;
354 wPreferences
.size_display
++;
355 wPreferences
.size_display
%= NUM_DISPLAYS
;
357 if (wPreferences
.size_display
== WDIS_NEW
) {
358 XUnmapWindow(dpy
, scr
->geometry_display
);
360 if (wPreferences
.size_display
== WDIS_CENTER
) {
361 moveGeometryDisplayCentered(scr
,
362 scr
->scr_width
/ 2, scr
->scr_height
/ 2);
363 } else if (wPreferences
.size_display
== WDIS_TOPLEFT
) {
364 moveGeometryDisplayCentered(scr
, 1, 1);
365 } else if (wPreferences
.size_display
== WDIS_FRAME_CENTER
) {
366 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
368 XMapRaised(dpy
, scr
->geometry_display
);
369 showGeometry(wwin
, x
, y
, x
+ w
, y
+ h
, dir
);
375 mapGeometryDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
)
377 WScreen
*scr
= wwin
->screen_ptr
;
379 if (wPreferences
.size_display
== WDIS_NEW
)
382 if (wPreferences
.size_display
== WDIS_CENTER
) {
383 moveGeometryDisplayCentered(scr
, scr
->scr_width
/ 2,
384 scr
->scr_height
/ 2);
385 } else if (wPreferences
.size_display
== WDIS_TOPLEFT
) {
386 moveGeometryDisplayCentered(scr
, 1, 1);
387 } else if (wPreferences
.size_display
== WDIS_FRAME_CENTER
) {
388 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
390 XMapRaised(dpy
, scr
->geometry_display
);
391 showGeometry(wwin
, x
, y
, x
+ w
, y
+ h
, 0);
394 #define unmapGeometryDisplay(w) \
395 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
398 checkEdgeResistance(WWindow
*wwin
, int *winx
, int *winy
, int off_x
, int off_y
)
400 int scr_width
= wwin
->screen_ptr
->scr_width
;
401 int scr_height
= wwin
->screen_ptr
->scr_height
;
404 int edge_resistance
= wPreferences
.edge_resistance
;
409 if ((x
+ wwin
->frame
->core
->width
) >= (scr_width
- 2)) {
410 if ((x
+ wwin
->frame
->core
->width
) < ((scr_width
- 2)
411 + edge_resistance
)) {
412 x
= scr_width
- wwin
->frame
->core
->width
- 2;
414 x
-= edge_resistance
;
419 if (x
> -edge_resistance
) {
422 x
+= edge_resistance
;
426 if ((y
+ wwin
->frame
->core
->height
) >= (scr_height
- 1)) {
427 if ((y
+ wwin
->frame
->core
->height
) < ((scr_height
- 1)
428 + edge_resistance
)) {
429 y
= scr_height
- wwin
->frame
->core
->height
- 1;
431 y
-= edge_resistance
;
436 if (y
> -edge_resistance
) {
439 y
+= edge_resistance
;
449 doWindowMove(WWindow
*wwin
, int single_win_x
, int single_win_y
,
450 LinkedList
*list
, int dx
, int dy
, int off_x
, int off_y
)
454 int scr_width
= wwin
->screen_ptr
->scr_width
;
455 int scr_height
= wwin
->screen_ptr
->scr_height
;
458 checkEdgeResistance(wwin
, &single_win_x
, &single_win_y
, off_x
, off_y
);
459 wWindowMove(wwin
, single_win_x
, single_win_y
);
463 x
= tmpw
->frame_x
+ dx
;
464 y
= tmpw
->frame_y
+ dy
;
466 /* don't let windows become unreachable */
468 if (x
+ (int)tmpw
->frame
->core
->width
< 20)
469 x
= 20 - (int)tmpw
->frame
->core
->width
;
470 else if (x
+ 20 > scr_width
)
473 if (y
+ (int)tmpw
->frame
->core
->height
< 20)
474 y
= 20 - (int)tmpw
->frame
->core
->height
;
475 else if (y
+ 20 > scr_height
)
478 wWindowMove(tmpw
, x
, y
);
486 drawTransparentFrame(WWindow
*wwin
, int x
, int y
, int width
, int height
)
488 Window root
= wwin
->screen_ptr
->root_win
;
489 GC gc
= wwin
->screen_ptr
->frame_gc
;
493 if (!wwin
->window_flags
.no_titlebar
&& !wwin
->flags
.shaded
) {
494 h
= wwin
->screen_ptr
->title_font
->height
+ TITLEBAR_EXTRA_HEIGHT
;
496 if (!wwin
->window_flags
.no_resizebar
&& !wwin
->flags
.shaded
) {
497 /* Can't use wwin-frame->bottom_width because, in some cases
498 (e.g. interactive placement), frame does not point to anything. */
499 bottom
= RESIZEBAR_HEIGHT
- 1;
501 XDrawRectangle(dpy
, root
, gc
, x
, y
, width
+ 1, height
+ 1);
504 XDrawLine(dpy
, root
, gc
, x
+ 1, y
+ h
, x
+ width
+ 1, y
+ h
);
507 XDrawLine(dpy
, root
, gc
, x
+ 1,
510 y
+ height
- bottom
);
516 drawFrames(WWindow
*wwin
, LinkedList
*list
, int dx
, int dy
, int off_x
, int off_y
)
519 int scr_width
= wwin
->screen_ptr
->scr_width
;
520 int scr_height
= wwin
->screen_ptr
->scr_height
;
525 x
= wwin
->frame_x
+ dx
;
526 y
= wwin
->frame_y
+ dy
;
528 checkEdgeResistance(wwin
, &x
, &y
, off_x
, off_y
);
529 drawTransparentFrame(wwin
, x
, y
,
530 wwin
->frame
->core
->width
,
531 wwin
->frame
->core
->height
);
536 x
= tmpw
->frame_x
+ dx
;
537 y
= tmpw
->frame_y
+ dy
;
539 /* don't let windows become unreachable */
541 if (x
+ (int)tmpw
->frame
->core
->width
< 20)
542 x
= 20 - (int)tmpw
->frame
->core
->width
;
543 else if (x
+ 20 > scr_width
)
546 if (y
+ (int)tmpw
->frame
->core
->height
< 20)
547 y
= 20 - (int)tmpw
->frame
->core
->height
;
548 else if (y
+ 20 > scr_height
)
551 drawTransparentFrame(tmpw
, x
, y
, tmpw
->frame
->core
->width
,
552 tmpw
->frame
->core
->height
);
567 while (XCheckMaskEvent(dpy
, ButtonMotionMask
, &ev
)) ;
572 crossWorkspace(WScreen
*scr
, WWindow
*wwin
, int opaque_move
,
573 int new_workspace
, int rewind
)
575 /* do not let window be unmapped */
577 wwin
->flags
.changing_workspace
= 1;
578 wWindowChangeWorkspace(wwin
, new_workspace
);
580 /* go to new workspace */
581 wWorkspaceChange(scr
, new_workspace
);
583 wwin
->flags
.changing_workspace
= 0;
586 XWarpPointer(dpy
, None
, None
, 0, 0, 0, 0, scr
->scr_width
- 20, 0);
588 XWarpPointer(dpy
, None
, None
, 0, 0, 0, 0, -(scr
->scr_width
- 20), 0);
593 XGrabPointer(dpy
, scr
->root_win
, True
, PointerMotionMask
594 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
595 GrabModeAsync
, None
, wCursor
[WCUR_MOVE
], CurrentTime
);
601 *----------------------------------------------------------------------
603 * Move the named window and the other selected ones (if any),
604 * interactively. Also shows the position of the window, if only one
605 * window is being moved.
606 * If the window is not on the selected window list, the selected
607 * windows are deselected.
608 * If shift is pressed during the operation, the position display
609 * is changed to another type.
612 * True if the window was moved, False otherwise.
615 * The window(s) position is changed, and the client(s) are
616 * notified about that.
617 * The position display configuration may be changed.
618 *----------------------------------------------------------------------
621 wMouseMoveWindow(WWindow
*wwin
, XEvent
*ev
)
623 WScreen
*scr
= wwin
->screen_ptr
;
625 Window root
= scr
->root_win
;
626 KeyCode shiftl
, shiftr
;
627 int w
= wwin
->frame
->core
->width
;
628 int h
= wwin
->frame
->core
->height
;
629 int x
= wwin
->frame_x
;
630 int y
= wwin
->frame_y
;
631 int ox
, oy
, orig_x
, orig_y
;
633 short count
= 0; /* for automatic workspace creation */
636 /* This needs not to change while moving, else bad things can happen */
637 int opaque_move
= wPreferences
.opaque_move
;
638 int XOffset
, YOffset
, origDragX
, origDragY
;
640 origDragX
= wwin
->frame_x
;
641 origDragY
= wwin
->frame_y
;
642 XOffset
= origDragX
- ev
->xbutton
.x_root
;
643 YOffset
= origDragY
- ev
->xbutton
.y_root
;
645 if (!wwin
->flags
.selected
) {
646 /* this window is not selected, unselect others and move only wwin */
649 orig_x
= ox
= ev
->xbutton
.x_root
;
650 orig_y
= oy
= ev
->xbutton
.y_root
;
651 off_x
= x
; off_y
= y
;
652 checkEdgeResistance(wwin
, &off_x
, &off_y
, 0, 0);
653 off_x
= (off_x
-x
); off_y
= (off_y
-y
);
655 puts("Moving window");
657 shiftl
= XKeysymToKeycode(dpy
, XK_Shift_L
);
658 shiftr
= XKeysymToKeycode(dpy
, XK_Shift_R
);
664 /* XWarpPointer() doesn't seem to generate Motion events, so
665 we've got to simulate them */
666 XQueryPointer(dpy
, root
, &junkw
, &junkw
, &event
.xmotion
.x_root
,
667 &event
.xmotion
.y_root
, &junk
, &junk
,
672 WMMaskEvent(dpy
, KeyPressMask
| ButtonMotionMask
673 | ButtonReleaseMask
| ButtonPressMask
| ExposureMask
, &event
);
675 if (event
.type
== MotionNotify
) {
676 /* compress MotionNotify events */
677 win
= event
.xmotion
.window
;
678 while (XCheckMaskEvent(dpy
, ButtonMotionMask
, &event
)) ;
681 switch (event
.type
) {
683 if (wSelectedWindows
)
685 if ((event
.xkey
.keycode
== shiftl
|| event
.xkey
.keycode
== shiftr
)
688 drawFrames(wwin
, wSelectedWindows
,
689 ox
- orig_x
, oy
- orig_y
, off_x
, off_y
);
691 cyclePositionDisplay(wwin
, x
, y
, w
, h
);
694 drawFrames(wwin
, wSelectedWindows
,
695 ox
- orig_x
, oy
- orig_y
, off_x
, off_y
);
697 showPosition(wwin
, x
, y
);
703 showPosition(wwin
, x
, y
);
706 drawFrames(wwin
, wSelectedWindows
,
707 ox
-orig_x
, oy
-orig_y
, off_x
, off_y
);
709 doWindowMove(wwin
, event
.xmotion
.x_root
+ XOffset
,
710 event
.xmotion
.y_root
+ YOffset
,
712 event
.xmotion
.x_root
- ox
,
713 event
.xmotion
.y_root
- oy
,
717 x
= event
.xmotion
.x_root
+ XOffset
;
718 y
= event
.xmotion
.y_root
+ YOffset
;
720 checkEdgeResistance(wwin
, &x
, &y
, off_x
, off_y
);
722 if (!wSelectedWindows
) {
723 if (wPreferences
.move_display
== WDIS_FRAME_CENTER
)
724 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
726 if (!warped
&& !wPreferences
.no_autowrap
) {
727 if (event
.xmotion
.x_root
<= 1) {
728 if (scr
->current_workspace
> 0) {
729 crossWorkspace(scr
, wwin
, opaque_move
,
730 scr
->current_workspace
-1, True
);
733 } else if (scr
->current_workspace
== 0
734 && wPreferences
.ws_cycle
) {
735 crossWorkspace(scr
, wwin
, opaque_move
,
736 scr
->workspace_count
-1, True
);
740 } else if (event
.xmotion
.x_root
>= scr
->scr_width
- 2) {
742 if (scr
->current_workspace
== scr
->workspace_count
-1) {
743 if ((!wPreferences
.ws_advance
&& wPreferences
.ws_cycle
)
744 || (scr
->workspace_count
== MAX_WORKSPACES
)) {
745 crossWorkspace(scr
, wwin
, opaque_move
, 0, False
);
749 /* if user insists on trying to go to next
750 workspace even when it's already the last,
752 else if ((ox
== event
.xmotion
.x_root
)
753 && wPreferences
.ws_advance
) {
755 /* detect user "rubbing" the window
758 && oy
- event
.xmotion
.y_root
> MOVE_THRESHOLD
)
759 count
= -(count
+ 1);
761 && event
.xmotion
.y_root
- oy
> MOVE_THRESHOLD
)
764 /* create a new workspace */
765 if (abs(count
) > 2) {
766 /* go to next workspace */
769 crossWorkspace(scr
, wwin
, opaque_move
,
770 scr
->current_workspace
+1, False
);
774 } else if (scr
->current_workspace
< scr
->workspace_count
) {
776 /* go to next workspace */
777 crossWorkspace(scr
, wwin
, opaque_move
,
778 scr
->current_workspace
+1, False
);
788 } else if (abs(orig_x
- event
.xmotion
.x_root
) >= MOVE_THRESHOLD
789 || abs(orig_y
- event
.xmotion
.y_root
) >= MOVE_THRESHOLD
) {
790 XChangeActivePointerGrab(dpy
, ButtonMotionMask
791 | ButtonReleaseMask
| ButtonPressMask
,
792 wCursor
[WCUR_MOVE
], CurrentTime
);
794 XGrabKeyboard(dpy
, root
, False
, GrabModeAsync
, GrabModeAsync
,
796 event
.xmotion
.x_root
= orig_x
;
797 event
.xmotion
.y_root
= orig_y
;
799 if (!wSelectedWindows
)
800 mapPositionDisplay(wwin
, x
, y
, w
, h
);
805 ox
= event
.xmotion
.x_root
;
806 oy
= event
.xmotion
.y_root
;
808 if (started
&& !opaque_move
)
809 drawFrames(wwin
, wSelectedWindows
, ox
- orig_x
, oy
- orig_y
, off_x
, off_y
);
811 showPosition(wwin
, x
, y
);
818 if (event
.xbutton
.button
!= ev
->xbutton
.button
)
823 drawFrames(wwin
, wSelectedWindows
,
824 ox
- orig_x
, oy
- orig_y
, off_x
, off_y
);
826 doWindowMove(wwin
, event
.xmotion
.x_root
+ XOffset
,
827 event
.xmotion
.y_root
+ YOffset
,
829 ox
- orig_x
, oy
- orig_y
,
832 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
833 wWindowSynthConfigureNotify(wwin
);
836 XUngrabKeyboard(dpy
, CurrentTime
);
839 wWindowChangeWorkspace(wwin
, scr
->current_workspace
);
840 wSetFocusTo(scr
, wwin
);
842 showPosition(wwin
, x
, y
);
843 if (!wSelectedWindows
) {
844 /* get rid of the geometry window */
845 unmapPositionDisplay(wwin
);
849 puts("End move window");
854 if (started
&& !opaque_move
) {
855 drawFrames(wwin
, wSelectedWindows
, ox
- orig_x
, oy
- orig_y
, off_x
, off_y
);
857 WMHandleEvent(&event
);
860 drawFrames(wwin
, wSelectedWindows
, ox
- orig_x
, oy
- orig_y
, off_x
, off_y
);
862 WMHandleEvent(&event
);
875 getResizeDirection(WWindow
*wwin
, int x
, int y
, int dx
, int dy
,
878 int w
= wwin
->frame
->core
->width
- 1;
879 int cw
= wwin
->frame
->resizebar_corner_width
;
882 /* if not resizing through the resizebar */
883 if (!(flags
& RESIZEBAR
)) {
884 int xdir
= (abs(x
) < (wwin
->client
.width
/2)) ? LEFT
: RIGHT
;
885 int ydir
= (abs(y
) < (wwin
->client
.height
/2)) ? UP
: DOWN
;
886 if (abs(dx
) < 2 || abs(dy
) < 2) {
887 if (abs(dy
) > abs(dx
))
892 return (xdir
| ydir
);
895 /* window is too narrow. allow diagonal resize */
899 if (flags
& HCONSTRAIN
)
904 return (LEFT
| ydir
);
906 return (RIGHT
| ydir
);
908 /* vertical resize */
909 if ((x
> cw
) && (x
< w
- cw
))
917 if ((abs(dy
) > 0) && !(flags
& HCONSTRAIN
))
925 wMouseResizeWindow(WWindow
*wwin
, XEvent
*ev
)
928 WScreen
*scr
= wwin
->screen_ptr
;
929 Window root
= scr
->root_win
;
930 int vert_border
= wwin
->frame
->top_width
+ wwin
->frame
->bottom_width
;
931 int fw
= wwin
->frame
->core
->width
;
932 int fh
= wwin
->frame
->core
->height
;
933 int fx
= wwin
->frame_x
;
934 int fy
= wwin
->frame_y
;
935 int is_resizebar
= (wwin
->frame
->resizebar
936 && ev
->xany
.window
==wwin
->frame
->resizebar
->window
);
940 int rw
= fw
, rh
= fh
;
941 int rx1
, ry1
, rx2
, ry2
;
943 KeyCode shiftl
, shiftr
;
950 if (wwin
->flags
.shaded
) {
951 wwarning("internal error: tryein");
954 orig_x
= ev
->xbutton
.x_root
;
955 orig_y
= ev
->xbutton
.y_root
;
959 puts("Resizing window");
967 shiftl
= XKeysymToKeycode(dpy
, XK_Shift_L
);
968 shiftr
= XKeysymToKeycode(dpy
, XK_Shift_R
);
969 if (!wwin
->window_flags
.no_titlebar
)
970 h
= wwin
->screen_ptr
->title_font
->height
+ TITLEBAR_EXTRA_HEIGHT
;
974 WMMaskEvent(dpy
, KeyPressMask
| ButtonMotionMask
| ButtonReleaseMask
975 | ButtonPressMask
| ExposureMask
, &event
);
976 switch (event
.type
) {
978 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
979 if ((event
.xkey
.keycode
== shiftl
|| event
.xkey
.keycode
== shiftr
)
981 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
982 cycleGeometryDisplay(wwin
, fx
, fy
, fw
, fh
, res
);
983 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
985 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
999 dw
= orig_x
- event
.xmotion
.x_root
;
1000 else if (res
& RIGHT
)
1001 dw
= event
.xmotion
.x_root
- orig_x
;
1003 dh
= orig_y
- event
.xmotion
.y_root
;
1004 else if (res
& DOWN
)
1005 dh
= event
.xmotion
.y_root
- orig_y
;
1007 orig_x
= event
.xmotion
.x_root
;
1008 orig_y
= event
.xmotion
.y_root
;
1013 fh
= rh
- vert_border
;
1014 wWindowConstrainSize(wwin
, &fw
, &fh
);
1018 else if (res
& RIGHT
)
1022 else if (res
& DOWN
)
1024 } else if (abs(orig_x
- event
.xmotion
.x_root
) >= MOVE_THRESHOLD
1025 || abs(orig_y
- event
.xmotion
.y_root
) >= MOVE_THRESHOLD
) {
1030 XTranslateCoordinates(dpy
, root
, wwin
->frame
->core
->window
,
1031 orig_x
, orig_y
, &tx
, &ty
, &junkw
);
1033 /* check if resizing through resizebar */
1039 if (is_resizebar
&& ((ev
->xbutton
.state
& ShiftMask
)
1040 || abs(orig_y
- event
.xmotion
.y_root
) < HRESIZE_THRESHOLD
))
1041 flags
|= HCONSTRAIN
;
1043 res
= getResizeDirection(wwin
, tx
, ty
,
1044 orig_x
- event
.xmotion
.x_root
,
1045 orig_y
- event
.xmotion
.y_root
, flags
);
1047 XChangeActivePointerGrab(dpy
, ButtonMotionMask
1048 | ButtonReleaseMask
| ButtonPressMask
,
1049 wCursor
[WCUR_RESIZE
], CurrentTime
);
1050 XGrabKeyboard(dpy
, root
, False
, GrabModeAsync
, GrabModeAsync
,
1055 /* Draw the resize frame for the first time. */
1056 mapGeometryDisplay(wwin
, fx
, fy
, fw
, fh
);
1058 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1060 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
1065 if (wPreferences
.size_display
== WDIS_FRAME_CENTER
) {
1066 drawTransparentFrame(wwin
, orig_fx
, orig_fy
,
1068 moveGeometryDisplayCentered(scr
, fx
+ fw
/ 2, fy
+ fh
/ 2);
1069 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1071 drawTransparentFrame(wwin
, orig_fx
, orig_fy
,
1073 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1075 if (fh
!= orig_fh
|| fw
!= orig_fw
) {
1076 if (wPreferences
.size_display
== WDIS_NEW
) {
1077 showGeometry(wwin
, orig_fx
, orig_fy
, orig_fx
+ orig_fw
,
1078 orig_fy
+ orig_fh
, res
);
1080 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
1089 if (event
.xbutton
.button
!= ev
->xbutton
.button
)
1093 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
1095 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1097 XUngrabKeyboard(dpy
, CurrentTime
);
1098 unmapGeometryDisplay(wwin
);
1100 wWindowConfigure(wwin
, fx
, fy
, fw
, fh
- vert_border
);
1103 puts("End resize window");
1108 WMHandleEvent(&event
);
1127 while (wSelectedWindows
) {
1128 wwin
= wSelectedWindows
->head
;
1129 if (wwin
->flags
.miniaturized
&& wwin
->icon
&& wwin
->icon
->selected
)
1130 wIconSelect(wwin
->icon
);
1132 XSetWindowBorder(dpy
, wwin
->frame
->core
->window
,
1133 wwin
->screen_ptr
->frame_border_pixel
);
1134 wwin
->flags
.selected
= 0;
1135 list_remove_head(&wSelectedWindows
);
1141 wSelectWindow(WWindow
*wwin
)
1143 if (!wwin
->flags
.selected
) {
1144 wwin
->flags
.selected
= 1;
1145 XSetWindowBorder(dpy
, wwin
->frame
->core
->window
,
1146 wwin
->screen_ptr
->white_pixel
);
1147 wSelectedWindows
= list_cons(wwin
, wSelectedWindows
);
1149 wwin
->flags
.selected
= 0;
1150 XSetWindowBorder(dpy
, wwin
->frame
->core
->window
,
1151 wwin
->screen_ptr
->frame_border_pixel
);
1152 wSelectedWindows
= list_remove_elem(wSelectedWindows
, wwin
);
1158 selectWindowsInside(WScreen
*scr
, int x1
, int y1
, int x2
, int y2
)
1162 /* select the windows and put them in the selected window list */
1163 tmpw
= scr
->focused_window
;
1164 while (tmpw
!= NULL
) {
1165 if (!(tmpw
->flags
.miniaturized
|| tmpw
->flags
.hidden
)) {
1166 if ((tmpw
->frame
->workspace
== scr
->current_workspace
1167 || tmpw
->window_flags
.omnipresent
)
1168 && (tmpw
->frame_x
>= x1
) && (tmpw
->frame_y
>= y1
)
1169 && (tmpw
->frame
->core
->width
+ tmpw
->frame_x
<= x2
)
1170 && (tmpw
->frame
->core
->height
+ tmpw
->frame_y
<= y2
)) {
1171 XSetWindowBorder(dpy
, tmpw
->frame
->core
->window
,
1172 tmpw
->screen_ptr
->white_pixel
);
1173 tmpw
->flags
.selected
= 1;
1174 wSelectedWindows
= list_cons(tmpw
, wSelectedWindows
);
1183 wSelectWindows(WScreen
*scr
, XEvent
*ev
)
1186 Window root
= scr
->root_win
;
1187 GC gc
= scr
->frame_gc
;
1188 int xp
= ev
->xbutton
.x_root
;
1189 int yp
= ev
->xbutton
.y_root
;
1194 puts("Selecting windows");
1196 if (XGrabPointer(dpy
, scr
->root_win
, False
, ButtonMotionMask
1197 | ButtonReleaseMask
| ButtonPressMask
, GrabModeAsync
,
1198 GrabModeAsync
, None
, wCursor
[WCUR_DEFAULT
],
1199 CurrentTime
) != Success
) {
1206 XDrawRectangle(dpy
, root
, gc
, xp
, yp
, w
, h
);
1208 WMMaskEvent(dpy
, ButtonReleaseMask
| PointerMotionMask
1209 | ButtonPressMask
, &event
);
1211 switch (event
.type
) {
1213 XDrawRectangle(dpy
, root
, gc
, x
, y
, w
, h
);
1214 x
= event
.xmotion
.x_root
;
1221 y
= event
.xmotion
.y_root
;
1228 XDrawRectangle(dpy
, root
, gc
, x
, y
, w
, h
);
1235 if (event
.xbutton
.button
!= ev
->xbutton
.button
)
1238 XDrawRectangle(dpy
, root
, gc
, x
, y
, w
, h
);
1240 XUngrabPointer(dpy
, CurrentTime
);
1241 selectWindowsInside(scr
, x
, y
, x
+ w
, y
+ h
);
1243 puts("End window selection");
1248 WMHandleEvent(&event
);
1255 InteractivePlaceWindow(WWindow
*wwin
, int *x_ret
, int *y_ret
)
1257 WScreen
*scr
= wwin
->screen_ptr
;
1258 Window root
= scr
->root_win
;
1260 int width
= wwin
->client
.width
;
1261 int height
= wwin
->client
.height
;
1263 KeyCode shiftl
, shiftr
;
1267 if (XGrabPointer(dpy
, root
, True
, PointerMotionMask
| ButtonPressMask
,
1268 GrabModeAsync
, GrabModeAsync
, None
,
1269 wCursor
[WCUR_DEFAULT
], CurrentTime
) != Success
) {
1274 if (!wwin
->window_flags
.no_titlebar
) {
1275 h
= scr
->title_font
->height
+ TITLEBAR_EXTRA_HEIGHT
;
1278 if (!wwin
->window_flags
.no_resizebar
) {
1279 height
+= RESIZEBAR_HEIGHT
;
1281 XGrabKeyboard(dpy
, root
, False
, GrabModeAsync
, GrabModeAsync
, CurrentTime
);
1282 XQueryPointer(dpy
, root
, &junkw
, &junkw
, &x
, &y
, &junk
, &junk
,
1283 (unsigned *) &junk
);
1284 mapPositionDisplay(wwin
, x
- width
/2, y
- h
/2, width
, height
);
1286 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
1288 shiftl
= XKeysymToKeycode(dpy
, XK_Shift_L
);
1289 shiftr
= XKeysymToKeycode(dpy
, XK_Shift_R
);
1291 WMMaskEvent(dpy
, PointerMotionMask
|ButtonPressMask
|ExposureMask
|KeyPressMask
,
1293 switch (event
.type
) {
1295 if ((event
.xkey
.keycode
== shiftl
)
1296 || (event
.xkey
.keycode
== shiftr
)) {
1297 drawTransparentFrame(wwin
,
1298 x
- width
/2, y
- h
/2, width
, height
);
1299 cyclePositionDisplay(wwin
,
1300 x
- width
/2, y
- h
/2, width
, height
);
1301 drawTransparentFrame(wwin
,
1302 x
- width
/2, y
- h
/2, width
, height
);
1307 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
1309 x
= event
.xmotion
.x_root
;
1310 y
= event
.xmotion
.y_root
;
1312 if (wPreferences
.move_display
== WDIS_FRAME_CENTER
)
1313 moveGeometryDisplayCentered(scr
, x
, y
+ (height
- h
) / 2);
1315 showPosition(wwin
, x
- width
/2, y
- h
/2);
1317 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
1322 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
1324 *x_ret
= x
- width
/2;
1326 XUngrabPointer(dpy
, CurrentTime
);
1327 XUngrabKeyboard(dpy
, CurrentTime
);
1328 /* get rid of the geometry window */
1329 unmapPositionDisplay(wwin
);
1333 WMHandleEvent(&event
);