2 * Window Maker 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
;
65 wGetGeometryWindowSize(WScreen
*scr
, unsigned int *width
,
69 *width
= XmbTextEscapement(scr
->info_text_font
->font
, "-8888 x -8888", 13);
70 *height
= (7 * scr
->info_text_font
->height
) / 4 - 1;
72 *width
= XTextWidth(scr
->info_text_font
->font
, "-8888 x -8888", 13);
73 *height
= (7 * scr
->info_text_font
->font
->ascent
) / 4 - 1;
79 *----------------------------------------------------------------------
80 * moveGeometryDisplayCentered
82 * routine that moves the geometry/position window on scr so it is
83 * centered over the given coordinates (x,y). Also the window position
84 * is clamped so it stays on the screen at all times.
85 *----------------------------------------------------------------------
88 moveGeometryDisplayCentered(WScreen
*scr
, int x
, int y
)
90 x
-= scr
->geometry_display_width
/ 2;
91 y
-= scr
->geometry_display_height
/ 2;
95 else if (x
> (scr
->scr_width
- scr
->geometry_display_width
- 3))
96 x
= scr
->scr_width
- scr
->geometry_display_width
- 3;
100 else if (y
> (scr
->scr_height
- scr
->geometry_display_height
- 3))
101 y
= scr
->scr_height
- scr
->geometry_display_height
- 3;
103 XMoveWindow(dpy
, scr
->geometry_display
, x
, y
);
108 showPosition(WWindow
*wwin
, int x
, int y
)
110 WScreen
*scr
= wwin
->screen_ptr
;
111 GC gc
= scr
->info_text_gc
;
115 if (wPreferences
.move_display
== WDIS_NEW
) {
117 int width
= wwin
->frame
->core
->width
;
118 int height
= wwin
->frame
->core
->height
;
120 GC lgc
= scr
->line_gc
;
121 XSetForeground(dpy
, lgc
, scr
->line_pixel
);
122 sprintf(num
, "%i", x
);
124 XDrawLine(dpy
, scr
->root_win
, lgc
, 0, y
-1, scr
->scr_width
, y
-1);
125 XDrawLine(dpy
, scr
->root_win
, lgc
, 0, y
+height
+2, scr
->scr_width
,
127 XDrawLine(dpy
, scr
->root_win
, lgc
, x
-1, 0, x
-1, scr
->scr_height
);
128 XDrawLine(dpy
, scr
->root_win
, lgc
, x
+width
+2, 0, x
+width
+2,
132 XClearArea(dpy
, scr
->geometry_display
, 1, 1,
133 scr
->geometry_display_width
-2, scr
->geometry_display_height
-2,
135 sprintf(num
, "%+i %-+i", x
, y
);
136 fw
= wTextWidth(scr
->info_text_font
->font
, num
, strlen(num
));
138 XSetForeground(dpy
, gc
, scr
->window_title_pixel
[WS_UNFOCUSED
]);
140 fh
= scr
->info_text_font
->height
;
141 wDrawString(scr
->geometry_display
, scr
->info_text_font
, gc
,
142 (scr
->geometry_display_width
- 2 - fw
) / 2,
143 (scr
->geometry_display_height
-fh
)/2 + scr
->info_text_font
->y
,
145 wDrawBevel(scr
->geometry_display
, scr
->geometry_display_width
+1,
146 scr
->geometry_display_height
+1, scr
->resizebar_texture
[0],
153 cyclePositionDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
)
155 WScreen
*scr
= wwin
->screen_ptr
;
157 wPreferences
.move_display
++;
158 wPreferences
.move_display
%= NUM_DISPLAYS
;
160 if (wPreferences
.move_display
== WDIS_NEW
) {
161 XUnmapWindow(dpy
, scr
->geometry_display
);
163 if (wPreferences
.move_display
== WDIS_CENTER
) {
164 moveGeometryDisplayCentered(scr
,
165 scr
->scr_width
/2, scr
->scr_height
/2);
166 } else if (wPreferences
.move_display
== WDIS_TOPLEFT
) {
167 moveGeometryDisplayCentered(scr
, 1, 1);
168 } else if (wPreferences
.move_display
== WDIS_FRAME_CENTER
) {
169 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
171 XMapRaised(dpy
, scr
->geometry_display
);
172 showPosition(wwin
, x
, y
);
178 mapPositionDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
)
180 WScreen
*scr
= wwin
->screen_ptr
;
182 if (wPreferences
.move_display
== WDIS_NEW
) {
184 } else if (wPreferences
.move_display
== WDIS_CENTER
) {
185 moveGeometryDisplayCentered(scr
, scr
->scr_width
/ 2,
186 scr
->scr_height
/ 2);
187 } else if (wPreferences
.move_display
== WDIS_TOPLEFT
) {
188 moveGeometryDisplayCentered(scr
, 1, 1);
189 } else if (wPreferences
.move_display
== WDIS_FRAME_CENTER
) {
190 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
192 XMapRaised(dpy
, scr
->geometry_display
);
193 showPosition(wwin
, x
, y
);
196 #define unmapPositionDisplay(w) \
197 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
201 showGeometry(WWindow
*wwin
, int x1
, int y1
, int x2
, int y2
, int direction
)
203 WScreen
*scr
= wwin
->screen_ptr
;
204 Window root
= scr
->root_win
;
205 GC gc
= scr
->line_gc
;
206 int ty
, by
, my
, x
, y
, mx
, s
;
211 ty
= y1
+ wwin
->frame
->top_width
;
212 by
= y2
- wwin
->frame
->bottom_width
;
213 fw
= wTextWidth(scr
->info_text_font
->font
, "8888", 4);
214 fh
= scr
->info_text_font
->height
;
216 if (wPreferences
.size_display
== WDIS_NEW
) {
217 XSetForeground(dpy
, gc
, scr
->line_pixel
);
219 /* vertical geometry */
220 if (((direction
& LEFT
) && (x2
< scr
->scr_width
- fw
)) || (x1
< fw
)) {
231 segment
[0].x1
= x
- (s
+ 6); segment
[0].y1
= ty
;
232 segment
[0].x2
= x
- (s
- 10); segment
[0].y2
= ty
;
235 segment
[1].x1
= x
- (s
- 2); segment
[1].y1
= ty
+ 1;
236 segment
[1].x2
= x
- (s
- 5); segment
[1].y2
= ty
+ 7;
238 segment
[2].x1
= x
- (s
- 2); segment
[2].y1
= ty
+ 1;
239 segment
[2].x2
= x
- (s
+ 1); segment
[2].y2
= ty
+ 7;
242 segment
[3].x1
= x
- (s
- 2); segment
[3].y1
= ty
+ 1;
243 segment
[3].x2
= x
- (s
- 2); segment
[3].y2
= my
- fh
/2 - 1;
245 XDrawSegments(dpy
, root
, gc
, segment
, 4);
253 segment
[1].y1
= by
- 1;
254 segment
[1].y2
= by
- 7;
256 segment
[2].y1
= by
- 1;
257 segment
[2].y2
= by
- 7;
260 segment
[3].y1
= my
+ fh
/2 + 2;
261 segment
[3].y2
= by
- 1;
263 XDrawSegments(dpy
, root
, gc
, segment
, 4);
265 sprintf(num
, "%i", (by
- ty
- wwin
->normal_hints
->base_height
) /
266 wwin
->normal_hints
->height_inc
);
267 fw
= wTextWidth(scr
->info_text_font
->font
, num
, strlen(num
));
269 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
271 /* Display the height. */
272 wDrawString(root
, scr
->info_text_font
, gc
,
273 x
- s
+ 3 - fw
/2, my
- fh
/2 + scr
->info_text_font
->y
+ 1,
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
= wTextWidth(scr
->info_text_font
->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 wDrawString(root
, scr
->info_text_font
, gc
,
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
= wTextWidth(scr
->info_text_font
->font
, num
, strlen(num
));
340 XSetForeground(dpy
, scr
->info_text_gc
,
341 scr
->window_title_pixel
[WS_UNFOCUSED
]);
343 /* Display the height. */
344 wDrawString(scr
->geometry_display
, scr
->info_text_font
,
346 (scr
->geometry_display_width
-fw
)/2,
347 (scr
->geometry_display_height
-fh
)/2 +scr
->info_text_font
->y
,
349 wDrawBevel(scr
->geometry_display
, scr
->geometry_display_width
+1,
350 scr
->geometry_display_height
+1, scr
->resizebar_texture
[0],
357 cycleGeometryDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
, int dir
)
359 WScreen
*scr
= wwin
->screen_ptr
;
361 wPreferences
.size_display
++;
362 wPreferences
.size_display
%= NUM_DISPLAYS
;
364 if (wPreferences
.size_display
== WDIS_NEW
) {
365 XUnmapWindow(dpy
, scr
->geometry_display
);
367 if (wPreferences
.size_display
== WDIS_CENTER
) {
368 moveGeometryDisplayCentered(scr
,
369 scr
->scr_width
/ 2, scr
->scr_height
/ 2);
370 } else if (wPreferences
.size_display
== WDIS_TOPLEFT
) {
371 moveGeometryDisplayCentered(scr
, 1, 1);
372 } else if (wPreferences
.size_display
== WDIS_FRAME_CENTER
) {
373 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
375 XMapRaised(dpy
, scr
->geometry_display
);
376 showGeometry(wwin
, x
, y
, x
+ w
, y
+ h
, dir
);
382 mapGeometryDisplay(WWindow
*wwin
, int x
, int y
, int w
, int h
)
384 WScreen
*scr
= wwin
->screen_ptr
;
386 if (wPreferences
.size_display
== WDIS_NEW
)
389 if (wPreferences
.size_display
== WDIS_CENTER
) {
390 moveGeometryDisplayCentered(scr
, scr
->scr_width
/ 2,
391 scr
->scr_height
/ 2);
392 } else if (wPreferences
.size_display
== WDIS_TOPLEFT
) {
393 moveGeometryDisplayCentered(scr
, 1, 1);
394 } else if (wPreferences
.size_display
== WDIS_FRAME_CENTER
) {
395 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
397 XMapRaised(dpy
, scr
->geometry_display
);
398 showGeometry(wwin
, x
, y
, x
+ w
, y
+ h
, 0);
401 #define unmapGeometryDisplay(w) \
402 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
405 checkEdgeResistance(WWindow
*wwin
, int *winx
, int *winy
, int off_x
, int off_y
)
407 int scr_width
= wwin
->screen_ptr
->scr_width
;
408 int scr_height
= wwin
->screen_ptr
->scr_height
;
411 int edge_resistance
= wPreferences
.edge_resistance
;
416 if ((x
+ wwin
->frame
->core
->width
) >= (scr_width
- 2)) {
417 if ((x
+ wwin
->frame
->core
->width
) < ((scr_width
- 2)
418 + edge_resistance
)) {
419 x
= scr_width
- wwin
->frame
->core
->width
- 2;
421 x
-= edge_resistance
;
426 if (x
> -edge_resistance
) {
429 x
+= edge_resistance
;
433 if ((y
+ wwin
->frame
->core
->height
) >= (scr_height
- 1)) {
434 if ((y
+ wwin
->frame
->core
->height
) < ((scr_height
- 1)
435 + edge_resistance
)) {
436 y
= scr_height
- wwin
->frame
->core
->height
- 1;
438 y
-= edge_resistance
;
443 if (y
> -edge_resistance
) {
446 y
+= edge_resistance
;
456 doWindowMove(WWindow
*wwin
, int single_win_x
, int single_win_y
,
457 LinkedList
*list
, int dx
, int dy
, int off_x
, int off_y
)
461 int scr_width
= wwin
->screen_ptr
->scr_width
;
462 int scr_height
= wwin
->screen_ptr
->scr_height
;
465 checkEdgeResistance(wwin
, &single_win_x
, &single_win_y
, off_x
, off_y
);
466 wWindowMove(wwin
, single_win_x
, single_win_y
);
470 x
= tmpw
->frame_x
+ dx
;
471 y
= tmpw
->frame_y
+ dy
;
473 /* don't let windows become unreachable */
475 if (x
+ (int)tmpw
->frame
->core
->width
< 20)
476 x
= 20 - (int)tmpw
->frame
->core
->width
;
477 else if (x
+ 20 > scr_width
)
480 if (y
+ (int)tmpw
->frame
->core
->height
< 20)
481 y
= 20 - (int)tmpw
->frame
->core
->height
;
482 else if (y
+ 20 > scr_height
)
485 wWindowMove(tmpw
, x
, y
);
493 drawTransparentFrame(WWindow
*wwin
, int x
, int y
, int width
, int height
)
495 Window root
= wwin
->screen_ptr
->root_win
;
496 GC gc
= wwin
->screen_ptr
->frame_gc
;
500 if (!wwin
->window_flags
.no_titlebar
&& !wwin
->flags
.shaded
) {
501 h
= wwin
->screen_ptr
->title_font
->height
+ TITLEBAR_EXTRA_HEIGHT
;
503 if (!wwin
->window_flags
.no_resizebar
&& !wwin
->flags
.shaded
) {
504 /* Can't use wwin-frame->bottom_width because, in some cases
505 (e.g. interactive placement), frame does not point to anything. */
506 bottom
= RESIZEBAR_HEIGHT
- 1;
508 XDrawRectangle(dpy
, root
, gc
, x
, y
, width
+ 1, height
+ 1);
511 XDrawLine(dpy
, root
, gc
, x
+ 1, y
+ h
, x
+ width
+ 1, y
+ h
);
514 XDrawLine(dpy
, root
, gc
, x
+ 1,
517 y
+ height
- bottom
);
523 drawFrames(WWindow
*wwin
, LinkedList
*list
, int dx
, int dy
, int off_x
, int off_y
)
526 int scr_width
= wwin
->screen_ptr
->scr_width
;
527 int scr_height
= wwin
->screen_ptr
->scr_height
;
532 x
= wwin
->frame_x
+ dx
;
533 y
= wwin
->frame_y
+ dy
;
535 checkEdgeResistance(wwin
, &x
, &y
, off_x
, off_y
);
536 drawTransparentFrame(wwin
, x
, y
,
537 wwin
->frame
->core
->width
,
538 wwin
->frame
->core
->height
);
543 x
= tmpw
->frame_x
+ dx
;
544 y
= tmpw
->frame_y
+ dy
;
546 /* don't let windows become unreachable */
548 if (x
+ (int)tmpw
->frame
->core
->width
< 20)
549 x
= 20 - (int)tmpw
->frame
->core
->width
;
550 else if (x
+ 20 > scr_width
)
553 if (y
+ (int)tmpw
->frame
->core
->height
< 20)
554 y
= 20 - (int)tmpw
->frame
->core
->height
;
555 else if (y
+ 20 > scr_height
)
558 drawTransparentFrame(tmpw
, x
, y
, tmpw
->frame
->core
->width
,
559 tmpw
->frame
->core
->height
);
573 while (XCheckMaskEvent(dpy
, ButtonMotionMask
, &ev
)) ;
578 crossWorkspace(WScreen
*scr
, WWindow
*wwin
, int opaque_move
,
579 int new_workspace
, int rewind
)
581 /* do not let window be unmapped */
583 wwin
->flags
.changing_workspace
= 1;
584 wWindowChangeWorkspace(wwin
, new_workspace
);
586 /* go to new workspace */
587 wWorkspaceChange(scr
, new_workspace
);
589 wwin
->flags
.changing_workspace
= 0;
592 XWarpPointer(dpy
, None
, None
, 0, 0, 0, 0, scr
->scr_width
- 20, 0);
594 XWarpPointer(dpy
, None
, None
, 0, 0, 0, 0, -(scr
->scr_width
- 20), 0);
599 XGrabPointer(dpy
, scr
->root_win
, True
, PointerMotionMask
600 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
601 GrabModeAsync
, None
, wCursor
[WCUR_MOVE
], CurrentTime
);
607 *----------------------------------------------------------------------
609 * Move the named window and the other selected ones (if any),
610 * interactively. Also shows the position of the window, if only one
611 * window is being moved.
612 * If the window is not on the selected window list, the selected
613 * windows are deselected.
614 * If shift is pressed during the operation, the position display
615 * is changed to another type.
618 * True if the window was moved, False otherwise.
621 * The window(s) position is changed, and the client(s) are
622 * notified about that.
623 * The position display configuration may be changed.
624 *----------------------------------------------------------------------
627 wMouseMoveWindow(WWindow
*wwin
, XEvent
*ev
)
629 WScreen
*scr
= wwin
->screen_ptr
;
631 Window root
= scr
->root_win
;
632 KeyCode shiftl
, shiftr
;
633 int w
= wwin
->frame
->core
->width
;
634 int h
= wwin
->frame
->core
->height
;
635 int x
= wwin
->frame_x
;
636 int y
= wwin
->frame_y
;
637 int ox
, oy
, orig_x
, orig_y
;
639 short count
= 0; /* for automatic workspace creation */
642 /* This needs not to change while moving, else bad things can happen */
643 int opaque_move
= wPreferences
.opaque_move
;
644 int XOffset
, YOffset
, origDragX
, origDragY
;
646 origDragX
= wwin
->frame_x
;
647 origDragY
= wwin
->frame_y
;
648 XOffset
= origDragX
- ev
->xbutton
.x_root
;
649 YOffset
= origDragY
- ev
->xbutton
.y_root
;
651 if (!wwin
->flags
.selected
) {
652 /* this window is not selected, unselect others and move only wwin */
653 wUnselectWindows(scr
);
655 orig_x
= ox
= ev
->xbutton
.x_root
;
656 orig_y
= oy
= ev
->xbutton
.y_root
;
657 off_x
= x
; off_y
= y
;
658 checkEdgeResistance(wwin
, &off_x
, &off_y
, 0, 0);
659 off_x
= (off_x
-x
); off_y
= (off_y
-y
);
661 puts("Moving window");
663 shiftl
= XKeysymToKeycode(dpy
, XK_Shift_L
);
664 shiftr
= XKeysymToKeycode(dpy
, XK_Shift_R
);
670 /* XWarpPointer() doesn't seem to generate Motion events, so
671 we've got to simulate them */
672 XQueryPointer(dpy
, root
, &junkw
, &junkw
, &event
.xmotion
.x_root
,
673 &event
.xmotion
.y_root
, &junk
, &junk
,
678 WMMaskEvent(dpy
, KeyPressMask
| ButtonMotionMask
679 | ButtonReleaseMask
| ButtonPressMask
| ExposureMask
, &event
);
681 if (event
.type
== MotionNotify
) {
682 /* compress MotionNotify events */
683 win
= event
.xmotion
.window
;
684 while (XCheckMaskEvent(dpy
, ButtonMotionMask
, &event
)) ;
687 switch (event
.type
) {
689 if (scr
->selected_windows
)
691 if ((event
.xkey
.keycode
== shiftl
|| event
.xkey
.keycode
== shiftr
)
694 drawFrames(wwin
, scr
->selected_windows
,
695 ox
- orig_x
, oy
- orig_y
, off_x
, off_y
);
697 cyclePositionDisplay(wwin
, x
, y
, w
, h
);
700 drawFrames(wwin
, scr
->selected_windows
,
701 ox
- orig_x
, oy
- orig_y
, off_x
, off_y
);
703 showPosition(wwin
, x
, y
);
709 showPosition(wwin
, x
, y
);
712 drawFrames(wwin
, scr
->selected_windows
,
713 ox
-orig_x
, oy
-orig_y
, off_x
, off_y
);
715 doWindowMove(wwin
, event
.xmotion
.x_root
+ XOffset
,
716 event
.xmotion
.y_root
+ YOffset
,
717 scr
->selected_windows
,
718 event
.xmotion
.x_root
- ox
,
719 event
.xmotion
.y_root
- oy
,
723 x
= event
.xmotion
.x_root
+ XOffset
;
724 y
= event
.xmotion
.y_root
+ YOffset
;
726 checkEdgeResistance(wwin
, &x
, &y
, off_x
, off_y
);
728 if (!scr
->selected_windows
) {
729 if (wPreferences
.move_display
== WDIS_FRAME_CENTER
)
730 moveGeometryDisplayCentered(scr
, x
+ w
/2, y
+ h
/2);
732 if (!warped
&& !wPreferences
.no_autowrap
) {
733 if (event
.xmotion
.x_root
<= 1) {
734 if (scr
->current_workspace
> 0) {
735 crossWorkspace(scr
, wwin
, opaque_move
,
736 scr
->current_workspace
-1, True
);
739 } else if (scr
->current_workspace
== 0
740 && wPreferences
.ws_cycle
) {
741 crossWorkspace(scr
, wwin
, opaque_move
,
742 scr
->workspace_count
-1, True
);
746 } else if (event
.xmotion
.x_root
>= scr
->scr_width
- 2) {
748 if (scr
->current_workspace
== scr
->workspace_count
-1) {
749 if ((!wPreferences
.ws_advance
&& wPreferences
.ws_cycle
)
750 || (scr
->workspace_count
== MAX_WORKSPACES
)) {
751 crossWorkspace(scr
, wwin
, opaque_move
, 0, False
);
755 /* if user insists on trying to go to next
756 workspace even when it's already the last,
758 else if ((ox
== event
.xmotion
.x_root
)
759 && wPreferences
.ws_advance
) {
761 /* detect user "rubbing" the window
764 && oy
- event
.xmotion
.y_root
> MOVE_THRESHOLD
)
765 count
= -(count
+ 1);
767 && event
.xmotion
.y_root
- oy
> MOVE_THRESHOLD
)
770 /* create a new workspace */
771 if (abs(count
) > 2) {
772 /* go to next workspace */
775 crossWorkspace(scr
, wwin
, opaque_move
,
776 scr
->current_workspace
+1, False
);
780 } else if (scr
->current_workspace
< scr
->workspace_count
) {
782 /* go to next workspace */
783 crossWorkspace(scr
, wwin
, opaque_move
,
784 scr
->current_workspace
+1, False
);
794 } else if (abs(orig_x
- event
.xmotion
.x_root
) >= MOVE_THRESHOLD
795 || abs(orig_y
- event
.xmotion
.y_root
) >= MOVE_THRESHOLD
) {
796 XChangeActivePointerGrab(dpy
, ButtonMotionMask
797 | ButtonReleaseMask
| ButtonPressMask
,
798 wCursor
[WCUR_MOVE
], CurrentTime
);
800 XGrabKeyboard(dpy
, root
, False
, GrabModeAsync
, GrabModeAsync
,
802 event
.xmotion
.x_root
= orig_x
;
803 event
.xmotion
.y_root
= orig_y
;
805 if (!scr
->selected_windows
)
806 mapPositionDisplay(wwin
, x
, y
, w
, h
);
811 ox
= event
.xmotion
.x_root
;
812 oy
= event
.xmotion
.y_root
;
814 if (started
&& !opaque_move
)
815 drawFrames(wwin
, scr
->selected_windows
, ox
- orig_x
, oy
- orig_y
, off_x
, off_y
);
817 showPosition(wwin
, x
, y
);
824 if (event
.xbutton
.button
!= ev
->xbutton
.button
)
829 drawFrames(wwin
, scr
->selected_windows
,
830 ox
- orig_x
, oy
- orig_y
, off_x
, off_y
);
832 doWindowMove(wwin
, event
.xmotion
.x_root
+ XOffset
,
833 event
.xmotion
.y_root
+ YOffset
,
834 scr
->selected_windows
,
835 ox
- orig_x
, oy
- orig_y
,
838 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
839 wWindowSynthConfigureNotify(wwin
);
842 XUngrabKeyboard(dpy
, CurrentTime
);
845 wWindowChangeWorkspace(wwin
, scr
->current_workspace
);
846 wSetFocusTo(scr
, wwin
);
848 showPosition(wwin
, x
, y
);
849 if (!scr
->selected_windows
) {
850 /* get rid of the geometry window */
851 unmapPositionDisplay(wwin
);
855 puts("End move window");
860 if (started
&& !opaque_move
) {
861 drawFrames(wwin
, scr
->selected_windows
, ox
- orig_x
, oy
- orig_y
, off_x
, off_y
);
863 WMHandleEvent(&event
);
866 drawFrames(wwin
, scr
->selected_windows
, ox
- orig_x
, oy
- orig_y
, off_x
, off_y
);
868 WMHandleEvent(&event
);
881 getResizeDirection(WWindow
*wwin
, int x
, int y
, int dx
, int dy
,
884 int w
= wwin
->frame
->core
->width
- 1;
885 int cw
= wwin
->frame
->resizebar_corner_width
;
888 /* if not resizing through the resizebar */
889 if (!(flags
& RESIZEBAR
)) {
890 int xdir
= (abs(x
) < (wwin
->client
.width
/2)) ? LEFT
: RIGHT
;
891 int ydir
= (abs(y
) < (wwin
->client
.height
/2)) ? UP
: DOWN
;
892 if (abs(dx
) < 2 || abs(dy
) < 2) {
893 if (abs(dy
) > abs(dx
))
898 return (xdir
| ydir
);
901 /* window is too narrow. allow diagonal resize */
905 if (flags
& HCONSTRAIN
)
910 return (LEFT
| ydir
);
912 return (RIGHT
| ydir
);
914 /* vertical resize */
915 if ((x
> cw
) && (x
< w
- cw
))
923 if ((abs(dy
) > 0) && !(flags
& HCONSTRAIN
))
931 wMouseResizeWindow(WWindow
*wwin
, XEvent
*ev
)
934 WScreen
*scr
= wwin
->screen_ptr
;
935 Window root
= scr
->root_win
;
936 int vert_border
= wwin
->frame
->top_width
+ wwin
->frame
->bottom_width
;
937 int fw
= wwin
->frame
->core
->width
;
938 int fh
= wwin
->frame
->core
->height
;
939 int fx
= wwin
->frame_x
;
940 int fy
= wwin
->frame_y
;
941 int is_resizebar
= (wwin
->frame
->resizebar
942 && ev
->xany
.window
==wwin
->frame
->resizebar
->window
);
946 int rw
= fw
, rh
= fh
;
947 int rx1
, ry1
, rx2
, ry2
;
949 KeyCode shiftl
, shiftr
;
956 if (wwin
->flags
.shaded
) {
957 wwarning("internal error: tryein");
960 orig_x
= ev
->xbutton
.x_root
;
961 orig_y
= ev
->xbutton
.y_root
;
965 puts("Resizing window");
968 wUnselectWindows(scr
);
973 shiftl
= XKeysymToKeycode(dpy
, XK_Shift_L
);
974 shiftr
= XKeysymToKeycode(dpy
, XK_Shift_R
);
975 if (!wwin
->window_flags
.no_titlebar
)
976 h
= wwin
->screen_ptr
->title_font
->height
+ TITLEBAR_EXTRA_HEIGHT
;
980 WMMaskEvent(dpy
, KeyPressMask
| ButtonMotionMask
| ButtonReleaseMask
981 | ButtonPressMask
| ExposureMask
, &event
);
982 switch (event
.type
) {
984 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
985 if ((event
.xkey
.keycode
== shiftl
|| event
.xkey
.keycode
== shiftr
)
987 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
988 cycleGeometryDisplay(wwin
, fx
, fy
, fw
, fh
, res
);
989 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
991 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
1005 dw
= orig_x
- event
.xmotion
.x_root
;
1006 else if (res
& RIGHT
)
1007 dw
= event
.xmotion
.x_root
- orig_x
;
1009 dh
= orig_y
- event
.xmotion
.y_root
;
1010 else if (res
& DOWN
)
1011 dh
= event
.xmotion
.y_root
- orig_y
;
1013 orig_x
= event
.xmotion
.x_root
;
1014 orig_y
= event
.xmotion
.y_root
;
1019 fh
= rh
- vert_border
;
1020 wWindowConstrainSize(wwin
, &fw
, &fh
);
1024 else if (res
& RIGHT
)
1028 else if (res
& DOWN
)
1030 } else if (abs(orig_x
- event
.xmotion
.x_root
) >= MOVE_THRESHOLD
1031 || abs(orig_y
- event
.xmotion
.y_root
) >= MOVE_THRESHOLD
) {
1036 XTranslateCoordinates(dpy
, root
, wwin
->frame
->core
->window
,
1037 orig_x
, orig_y
, &tx
, &ty
, &junkw
);
1039 /* check if resizing through resizebar */
1045 if (is_resizebar
&& ((ev
->xbutton
.state
& ShiftMask
)
1046 || abs(orig_y
- event
.xmotion
.y_root
) < HRESIZE_THRESHOLD
))
1047 flags
|= HCONSTRAIN
;
1049 res
= getResizeDirection(wwin
, tx
, ty
,
1050 orig_x
- event
.xmotion
.x_root
,
1051 orig_y
- event
.xmotion
.y_root
, flags
);
1053 XChangeActivePointerGrab(dpy
, ButtonMotionMask
1054 | ButtonReleaseMask
| ButtonPressMask
,
1055 wCursor
[WCUR_RESIZE
], CurrentTime
);
1056 XGrabKeyboard(dpy
, root
, False
, GrabModeAsync
, GrabModeAsync
,
1061 /* Draw the resize frame for the first time. */
1062 mapGeometryDisplay(wwin
, fx
, fy
, fw
, fh
);
1064 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1066 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
1071 if (wPreferences
.size_display
== WDIS_FRAME_CENTER
) {
1072 drawTransparentFrame(wwin
, orig_fx
, orig_fy
,
1074 moveGeometryDisplayCentered(scr
, fx
+ fw
/ 2, fy
+ fh
/ 2);
1075 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1077 drawTransparentFrame(wwin
, orig_fx
, orig_fy
,
1079 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1081 if (fh
!= orig_fh
|| fw
!= orig_fw
) {
1082 if (wPreferences
.size_display
== WDIS_NEW
) {
1083 showGeometry(wwin
, orig_fx
, orig_fy
, orig_fx
+ orig_fw
,
1084 orig_fy
+ orig_fh
, res
);
1086 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
1095 if (event
.xbutton
.button
!= ev
->xbutton
.button
)
1099 showGeometry(wwin
, fx
, fy
, fx
+ fw
, fy
+ fh
, res
);
1101 drawTransparentFrame(wwin
, fx
, fy
, fw
, fh
);
1103 XUngrabKeyboard(dpy
, CurrentTime
);
1104 unmapGeometryDisplay(wwin
);
1106 wWindowConfigure(wwin
, fx
, fy
, fw
, fh
- vert_border
);
1109 puts("End resize window");
1114 WMHandleEvent(&event
);
1129 wUnselectWindows(WScreen
*scr
)
1133 while (scr
->selected_windows
) {
1134 wwin
= scr
->selected_windows
->head
;
1135 if (wwin
->flags
.miniaturized
&& wwin
->icon
&& wwin
->icon
->selected
)
1136 wIconSelect(wwin
->icon
);
1138 wSelectWindow(wwin
, False
);
1144 selectWindowsInside(WScreen
*scr
, int x1
, int y1
, int x2
, int y2
)
1148 /* select the windows and put them in the selected window list */
1149 tmpw
= scr
->focused_window
;
1150 while (tmpw
!= NULL
) {
1151 if (!(tmpw
->flags
.miniaturized
|| tmpw
->flags
.hidden
)) {
1152 if ((tmpw
->frame
->workspace
== scr
->current_workspace
1153 || tmpw
->window_flags
.omnipresent
)
1154 && (tmpw
->frame_x
>= x1
) && (tmpw
->frame_y
>= y1
)
1155 && (tmpw
->frame
->core
->width
+ tmpw
->frame_x
<= x2
)
1156 && (tmpw
->frame
->core
->height
+ tmpw
->frame_y
<= y2
)) {
1157 wSelectWindow(tmpw
, True
);
1166 wSelectWindows(WScreen
*scr
, XEvent
*ev
)
1169 Window root
= scr
->root_win
;
1170 GC gc
= scr
->frame_gc
;
1171 int xp
= ev
->xbutton
.x_root
;
1172 int yp
= ev
->xbutton
.y_root
;
1177 puts("Selecting windows");
1179 if (XGrabPointer(dpy
, scr
->root_win
, False
, ButtonMotionMask
1180 | ButtonReleaseMask
| ButtonPressMask
, GrabModeAsync
,
1181 GrabModeAsync
, None
, wCursor
[WCUR_DEFAULT
],
1182 CurrentTime
) != Success
) {
1187 wUnselectWindows(scr
);
1189 XDrawRectangle(dpy
, root
, gc
, xp
, yp
, w
, h
);
1191 WMMaskEvent(dpy
, ButtonReleaseMask
| PointerMotionMask
1192 | ButtonPressMask
, &event
);
1194 switch (event
.type
) {
1196 XDrawRectangle(dpy
, root
, gc
, x
, y
, w
, h
);
1197 x
= event
.xmotion
.x_root
;
1204 y
= event
.xmotion
.y_root
;
1211 XDrawRectangle(dpy
, root
, gc
, x
, y
, w
, h
);
1218 if (event
.xbutton
.button
!= ev
->xbutton
.button
)
1221 XDrawRectangle(dpy
, root
, gc
, x
, y
, w
, h
);
1223 XUngrabPointer(dpy
, CurrentTime
);
1224 selectWindowsInside(scr
, x
, y
, x
+ w
, y
+ h
);
1226 puts("End window selection");
1231 WMHandleEvent(&event
);
1238 InteractivePlaceWindow(WWindow
*wwin
, int *x_ret
, int *y_ret
,
1239 unsigned width
, unsigned height
)
1241 WScreen
*scr
= wwin
->screen_ptr
;
1242 Window root
= scr
->root_win
;
1245 KeyCode shiftl
, shiftr
;
1249 if (XGrabPointer(dpy
, root
, True
, PointerMotionMask
| ButtonPressMask
,
1250 GrabModeAsync
, GrabModeAsync
, None
,
1251 wCursor
[WCUR_DEFAULT
], CurrentTime
) != Success
) {
1256 if (!wwin
->window_flags
.no_titlebar
) {
1257 h
= scr
->title_font
->height
+ TITLEBAR_EXTRA_HEIGHT
;
1260 if (!wwin
->window_flags
.no_resizebar
) {
1261 height
+= RESIZEBAR_HEIGHT
;
1263 XGrabKeyboard(dpy
, root
, False
, GrabModeAsync
, GrabModeAsync
, CurrentTime
);
1264 XQueryPointer(dpy
, root
, &junkw
, &junkw
, &x
, &y
, &junk
, &junk
,
1265 (unsigned *) &junk
);
1266 mapPositionDisplay(wwin
, x
- width
/2, y
- h
/2, width
, height
);
1268 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
1270 shiftl
= XKeysymToKeycode(dpy
, XK_Shift_L
);
1271 shiftr
= XKeysymToKeycode(dpy
, XK_Shift_R
);
1273 WMMaskEvent(dpy
, PointerMotionMask
|ButtonPressMask
|ExposureMask
|KeyPressMask
,
1275 switch (event
.type
) {
1277 if ((event
.xkey
.keycode
== shiftl
)
1278 || (event
.xkey
.keycode
== shiftr
)) {
1279 drawTransparentFrame(wwin
,
1280 x
- width
/2, y
- h
/2, width
, height
);
1281 cyclePositionDisplay(wwin
,
1282 x
- width
/2, y
- h
/2, width
, height
);
1283 drawTransparentFrame(wwin
,
1284 x
- width
/2, y
- h
/2, width
, height
);
1289 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
1291 x
= event
.xmotion
.x_root
;
1292 y
= event
.xmotion
.y_root
;
1294 if (wPreferences
.move_display
== WDIS_FRAME_CENTER
)
1295 moveGeometryDisplayCentered(scr
, x
, y
+ (height
- h
) / 2);
1297 showPosition(wwin
, x
- width
/2, y
- h
/2);
1299 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
1304 drawTransparentFrame(wwin
, x
- width
/2, y
- h
/2, width
, height
);
1306 *x_ret
= x
- width
/2;
1308 XUngrabPointer(dpy
, CurrentTime
);
1309 XUngrabKeyboard(dpy
, CurrentTime
);
1310 /* get rid of the geometry window */
1311 unmapPositionDisplay(wwin
);
1315 WMHandleEvent(&event
);