Update to Window Maker 0.50.2
[wmaker-crm.git] / src / moveres.c
blob9931179273a09e9d661ea910cd38e3bf5c6f528b
1 /*
2 * Window Maker window manager
3 *
4 * Copyright (c) 1997, 1998 Alfredo K. Kojima
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
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,
19 * USA.
22 #include "wconfig.h"
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
26 #include <X11/keysym.h>
27 #include <stdio.h>
28 #include <unistd.h>
30 #include "WindowMaker.h"
31 #include "wcore.h"
32 #include "framewin.h"
33 #include "window.h"
34 #include "client.h"
35 #include "icon.h"
36 #include "dock.h"
37 #include "funcs.h"
38 #include "actions.h"
39 #include "workspace.h"
41 #include "list.h"
43 /* How many different types of geometry/position
44 display thingies are there? */
45 #define NUM_DISPLAYS 4
47 #define LEFT 1
48 #define RIGHT 2
49 #define HORIZONTAL (LEFT|RIGHT)
50 #define UP 4
51 #define DOWN 8
52 #define VERTICAL (UP|DOWN)
54 /****** Global Variables ******/
55 extern Time LastTimestamp;
57 extern Cursor wCursor[WCUR_LAST];
59 extern WPreferences wPreferences;
61 extern Atom _XA_WM_PROTOCOLS;
65 void
66 wGetGeometryWindowSize(WScreen *scr, unsigned int *width,
67 unsigned int *height)
69 #ifdef I18N_MB
70 *width = XmbTextEscapement(scr->info_text_font->font, "-8888 x -8888", 13);
71 *height = (7 * scr->info_text_font->height) / 4 - 1;
72 #else
73 *width = XTextWidth(scr->info_text_font->font, "-8888 x -8888", 13);
74 *height = (7 * scr->info_text_font->font->ascent) / 4 - 1;
75 #endif
80 *----------------------------------------------------------------------
81 * moveGeometryDisplayCentered
83 * routine that moves the geometry/position window on scr so it is
84 * centered over the given coordinates (x,y). Also the window position
85 * is clamped so it stays on the screen at all times.
86 *----------------------------------------------------------------------
88 static void
89 moveGeometryDisplayCentered(WScreen *scr, int x, int y)
91 x -= scr->geometry_display_width / 2;
92 y -= scr->geometry_display_height / 2;
94 if (x < 1)
95 x = 1;
96 else if (x > (scr->scr_width - scr->geometry_display_width - 3))
97 x = scr->scr_width - scr->geometry_display_width - 3;
99 if (y < 1)
100 y = 1;
101 else if (y > (scr->scr_height - scr->geometry_display_height - 3))
102 y = scr->scr_height - scr->geometry_display_height - 3;
104 XMoveWindow(dpy, scr->geometry_display, x, y);
108 static void
109 showPosition(WWindow *wwin, int x, int y)
111 WScreen *scr = wwin->screen_ptr;
112 GC gc = scr->info_text_gc;
113 char num[16];
114 int fw, fh;
116 if (wPreferences.move_display == WDIS_NEW) {
117 #if 0
118 int width = wwin->frame->core->width;
119 int height = wwin->frame->core->height;
121 GC lgc = scr->line_gc;
122 XSetForeground(dpy, lgc, scr->line_pixel);
123 sprintf(num, "%i", x);
125 XDrawLine(dpy, scr->root_win, lgc, 0, y-1, scr->scr_width, y-1);
126 XDrawLine(dpy, scr->root_win, lgc, 0, y+height+2, scr->scr_width,
127 y+height+2);
128 XDrawLine(dpy, scr->root_win, lgc, x-1, 0, x-1, scr->scr_height);
129 XDrawLine(dpy, scr->root_win, lgc, x+width+2, 0, x+width+2,
130 scr->scr_height);
131 #endif
132 } else {
133 XClearArea(dpy, scr->geometry_display, 1, 1,
134 scr->geometry_display_width-2, scr->geometry_display_height-2,
135 False);
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,
145 num, strlen(num));
146 wDrawBevel(scr->geometry_display, scr->geometry_display_width+1,
147 scr->geometry_display_height+1, scr->resizebar_texture[0],
148 WREL_RAISED);
153 static void
154 cyclePositionDisplay(WWindow *wwin, int x, int y, int w, int h)
156 WScreen *scr = wwin->screen_ptr;
158 wPreferences.move_display++;
159 wPreferences.move_display %= NUM_DISPLAYS;
161 if (wPreferences.move_display == WDIS_NEW) {
162 XUnmapWindow(dpy, scr->geometry_display);
163 } else {
164 if (wPreferences.move_display == WDIS_CENTER) {
165 moveGeometryDisplayCentered(scr,
166 scr->scr_width/2, scr->scr_height/2);
167 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
168 moveGeometryDisplayCentered(scr, 1, 1);
169 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
170 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
172 XMapRaised(dpy, scr->geometry_display);
173 showPosition(wwin, x, y);
178 static void
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) {
184 return;
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);
201 static void
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;
208 char num[16];
209 XSegment segment[4];
210 int fw, fh;
212 ty = y1 + wwin->frame->top_width;
213 by = y2 - wwin->frame->bottom_width;
214 fw = wTextWidth(scr->info_text_font->font, "8888", 4);
215 fh = scr->info_text_font->height;
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)) {
222 x = x2;
223 s = -15;
224 } else {
225 x = x1;
226 s = 15;
228 my = (ty + by) / 2;
230 /* top arrow */
231 /* end bar */
232 segment[0].x1 = x - (s + 6); segment[0].y1 = ty;
233 segment[0].x2 = x - (s - 10); segment[0].y2 = ty;
235 /* arrowhead */
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;
242 /* line */
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);
248 /* bottom arrow */
249 /* end bar */
250 segment[0].y1 = by;
251 segment[0].y2 = by;
253 /* arrowhead */
254 segment[1].y1 = by - 1;
255 segment[1].y2 = by - 7;
257 segment[2].y1 = by - 1;
258 segment[2].y2 = by - 7;
260 /* line */
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 = wTextWidth(scr->info_text_font->font, num, strlen(num));
270 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
272 /* Display the height. */
273 wDrawString(root, scr->info_text_font, gc,
274 x - s + 3 - fw/2, my - fh/2 + scr->info_text_font->y + 1,
275 num, strlen(num));
276 XSetForeground(dpy, gc, scr->line_pixel);
277 /* horizontal geometry */
278 if (y1 < 15) {
279 y = y2;
280 s = -15;
281 } else {
282 y = y1;
283 s = 15;
285 mx = x1 + (x2 - x1)/2;
286 sprintf(num, "%i", (x2 - x1 - wwin->normal_hints->base_width) /
287 wwin->normal_hints->width_inc);
288 fw = wTextWidth(scr->info_text_font->font, num, strlen(num));
290 /* left arrow */
291 /* end bar */
292 segment[0].x1 = x1; segment[0].y1 = y - (s + 6);
293 segment[0].x2 = x1; segment[0].y2 = y - (s - 10);
295 /* arrowhead */
296 segment[1].x1 = x1 + 7; segment[1].y1 = y - (s + 1);
297 segment[1].x2 = x1 + 1; segment[1].y2 = y - (s - 2);
299 segment[2].x1 = x1 + 1; segment[2].y1 = y - (s - 2);
300 segment[2].x2 = x1 + 7; segment[2].y2 = y - (s - 5);
302 /* line */
303 segment[3].x1 = x1 + 1; segment[3].y1 = y - (s - 2);
304 segment[3].x2 = mx - fw/2 - 2; segment[3].y2 = y - (s - 2);
306 XDrawSegments(dpy, root, gc, segment, 4);
308 /* right arrow */
309 /* end bar */
310 segment[0].x1 = x2 + 1;
311 segment[0].x2 = x2 + 1;
313 /* arrowhead */
314 segment[1].x1 = x2 - 6;
315 segment[1].x2 = x2;
317 segment[2].x1 = x2;
318 segment[2].x2 = x2 - 6;
320 /* line */
321 segment[3].x1 = mx + fw/2 + 2;
322 segment[3].x2 = x2;
324 XDrawSegments(dpy, root, gc, segment, 4);
326 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
328 /* Display the width. */
329 wDrawString(root, scr->info_text_font, gc,
330 mx - fw/2 + 1, y - s + fh/2 + 1, num, strlen(num));
331 } else {
332 XClearArea(dpy, scr->geometry_display, 1, 1,
333 scr->geometry_display_width-2, scr->geometry_display_height-2,
334 False);
335 sprintf(num, "%i x %-i", (x2 - x1 - wwin->normal_hints->base_width)
336 / wwin->normal_hints->width_inc,
337 (by - ty - wwin->normal_hints->base_height)
338 / wwin->normal_hints->height_inc);
339 fw = wTextWidth(scr->info_text_font->font, num, strlen(num));
341 XSetForeground(dpy, scr->info_text_gc,
342 scr->window_title_pixel[WS_UNFOCUSED]);
344 /* Display the height. */
345 wDrawString(scr->geometry_display, scr->info_text_font,
346 scr->info_text_gc,
347 (scr->geometry_display_width-fw)/2,
348 (scr->geometry_display_height-fh)/2 +scr->info_text_font->y,
349 num, strlen(num));
350 wDrawBevel(scr->geometry_display, scr->geometry_display_width+1,
351 scr->geometry_display_height+1, scr->resizebar_texture[0],
352 WREL_RAISED);
357 static void
358 cycleGeometryDisplay(WWindow *wwin, int x, int y, int w, int h, int dir)
360 WScreen *scr = wwin->screen_ptr;
362 wPreferences.size_display++;
363 wPreferences.size_display %= NUM_DISPLAYS;
365 if (wPreferences.size_display == WDIS_NEW) {
366 XUnmapWindow(dpy, scr->geometry_display);
367 } else {
368 if (wPreferences.size_display == WDIS_CENTER) {
369 moveGeometryDisplayCentered(scr,
370 scr->scr_width / 2, scr->scr_height / 2);
371 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
372 moveGeometryDisplayCentered(scr, 1, 1);
373 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
374 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
376 XMapRaised(dpy, scr->geometry_display);
377 showGeometry(wwin, x, y, x + w, y + h, dir);
382 static void
383 mapGeometryDisplay(WWindow *wwin, int x, int y, int w, int h)
385 WScreen *scr = wwin->screen_ptr;
387 if (wPreferences.size_display == WDIS_NEW)
388 return;
390 if (wPreferences.size_display == WDIS_CENTER) {
391 moveGeometryDisplayCentered(scr, scr->scr_width / 2,
392 scr->scr_height / 2);
393 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
394 moveGeometryDisplayCentered(scr, 1, 1);
395 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
396 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
398 XMapRaised(dpy, scr->geometry_display);
399 showGeometry(wwin, x, y, x + w, y + h, 0);
402 #define unmapGeometryDisplay(w) \
403 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
405 static void
406 checkEdgeResistance(WWindow *wwin, int *winx, int *winy, int off_x, int off_y)
408 WScreen *scr = wwin->screen_ptr;
409 int scr_width = wwin->screen_ptr->scr_width - 3;
410 int scr_height = wwin->screen_ptr->scr_height;
411 int x = *winx;
412 int y = *winy;
413 int edge_resistance = wPreferences.edge_resistance;
414 int right_side = scr_width;
415 int left_side = 0;
416 int isize = wPreferences.icon_size;
418 x -= off_x;
419 y -= off_y;
421 if (scr->dock)
423 if (scr->dock->on_right_side)
424 right_side -= isize + DOCK_EXTRA_SPACE;
425 else
426 left_side += isize + DOCK_EXTRA_SPACE;
429 if ((x + wwin->frame->core->width) >= right_side) {
430 if ((x + wwin->frame->core->width) < (right_side
431 + edge_resistance)) {
432 x = right_side - wwin->frame->core->width;
433 } else {
434 x -= edge_resistance;
438 if (x <= left_side) {
439 if (x > (left_side - edge_resistance)) {
440 x = left_side;
441 } else {
442 x += edge_resistance;
446 if ((y + wwin->frame->core->height) >= (scr_height - 1)) {
447 if ((y + wwin->frame->core->height) < ((scr_height - 1)
448 + edge_resistance)) {
449 y = scr_height - wwin->frame->core->height - 1;
450 } else {
451 y -= edge_resistance;
455 if (y <=0) {
456 if (y > -edge_resistance) {
457 y = 0;
458 } else {
459 y += edge_resistance;
464 *winx = x;
465 *winy = y;
468 static void
469 doWindowMove(WWindow *wwin, int single_win_x, int single_win_y,
470 LinkedList *list, int dx, int dy, int off_x, int off_y)
472 WWindow *tmpw;
473 int x, y;
474 int scr_width = wwin->screen_ptr->scr_width;
475 int scr_height = wwin->screen_ptr->scr_height;
477 if (!list) {
478 checkEdgeResistance(wwin, &single_win_x, &single_win_y, off_x, off_y);
479 wWindowMove(wwin, single_win_x, single_win_y);
480 } else {
481 while (list) {
482 tmpw = list->head;
483 x = tmpw->frame_x + dx;
484 y = tmpw->frame_y + dy;
486 /* don't let windows become unreachable */
488 if (x + (int)tmpw->frame->core->width < 20)
489 x = 20 - (int)tmpw->frame->core->width;
490 else if (x + 20 > scr_width)
491 x = scr_width - 20;
493 if (y + (int)tmpw->frame->core->height < 20)
494 y = 20 - (int)tmpw->frame->core->height;
495 else if (y + 20 > scr_height)
496 y = scr_height - 20;
498 wWindowMove(tmpw, x, y);
499 list = list->tail;
505 static void
506 drawTransparentFrame(WWindow *wwin, int x, int y, int width, int height)
508 Window root = wwin->screen_ptr->root_win;
509 GC gc = wwin->screen_ptr->frame_gc;
510 int h = 0;
511 int bottom = 0;
513 if (!WFLAGP(wwin, no_titlebar) && !wwin->flags.shaded) {
514 h = wwin->screen_ptr->title_font->height + TITLEBAR_EXTRA_HEIGHT;
516 if (!WFLAGP(wwin, no_resizebar) && !wwin->flags.shaded) {
517 /* Can't use wwin-frame->bottom_width because, in some cases
518 (e.g. interactive placement), frame does not point to anything. */
519 bottom = RESIZEBAR_HEIGHT - 1;
521 XDrawRectangle(dpy, root, gc, x, y, width + 1, height + 1);
523 if (h > 0) {
524 XDrawLine(dpy, root, gc, x + 1, y + h, x + width + 1, y + h);
526 if (bottom > 0) {
527 XDrawLine(dpy, root, gc, x + 1,
528 y + height - bottom,
529 x + width + 1,
530 y + height - bottom);
535 static void
536 drawFrames(WWindow *wwin, LinkedList *list, int dx, int dy, int off_x, int off_y)
538 WWindow *tmpw;
539 int scr_width = wwin->screen_ptr->scr_width;
540 int scr_height = wwin->screen_ptr->scr_height;
541 int x, y;
543 if (!list) {
545 x = wwin->frame_x + dx;
546 y = wwin->frame_y + dy;
548 checkEdgeResistance(wwin, &x, &y, off_x, off_y);
549 drawTransparentFrame(wwin, x, y,
550 wwin->frame->core->width,
551 wwin->frame->core->height);
553 } else {
554 while (list) {
555 tmpw = list->head;
556 x = tmpw->frame_x + dx;
557 y = tmpw->frame_y + dy;
559 /* don't let windows become unreachable */
561 if (x + (int)tmpw->frame->core->width < 20)
562 x = 20 - (int)tmpw->frame->core->width;
563 else if (x + 20 > scr_width)
564 x = scr_width - 20;
566 if (y + (int)tmpw->frame->core->height < 20)
567 y = 20 - (int)tmpw->frame->core->height;
568 else if (y + 20 > scr_height)
569 y = scr_height - 20;
571 drawTransparentFrame(tmpw, x, y, tmpw->frame->core->width,
572 tmpw->frame->core->height);
574 list = list->tail;
581 static void
582 flushMotion()
584 XEvent ev;
586 XSync(dpy, False);
587 while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
591 static void
592 crossWorkspace(WScreen *scr, WWindow *wwin, int opaque_move,
593 int new_workspace, int rewind)
595 /* do not let window be unmapped */
596 if (opaque_move) {
597 wwin->flags.changing_workspace = 1;
598 wWindowChangeWorkspace(wwin, new_workspace);
600 /* go to new workspace */
601 wWorkspaceChange(scr, new_workspace);
603 wwin->flags.changing_workspace = 0;
605 if (rewind)
606 XWarpPointer(dpy, None, None, 0, 0, 0, 0, scr->scr_width - 20, 0);
607 else
608 XWarpPointer(dpy, None, None, 0, 0, 0, 0, -(scr->scr_width - 20), 0);
610 flushMotion();
612 if (!opaque_move) {
613 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
614 |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
615 GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
621 *----------------------------------------------------------------------
622 * wMouseMoveWindow--
623 * Move the named window and the other selected ones (if any),
624 * interactively. Also shows the position of the window, if only one
625 * window is being moved.
626 * If the window is not on the selected window list, the selected
627 * windows are deselected.
628 * If shift is pressed during the operation, the position display
629 * is changed to another type.
631 * Returns:
632 * True if the window was moved, False otherwise.
634 * Side effects:
635 * The window(s) position is changed, and the client(s) are
636 * notified about that.
637 * The position display configuration may be changed.
638 *----------------------------------------------------------------------
641 #if 0
642 typedef struct _looper {
643 WWindow *wwin;
644 int x,y,w,h,ox,oy;
645 } _looper;
647 void
648 _keyloop(_looper *lpr){
649 WWindow *wwin = lpr->wwin;
650 WScreen *scr = wwin->screen_ptr;
651 int w = wwin->frame->core->width;
652 int h = wwin->frame->core->height;
653 int src_x = wwin->frame_x;
654 int src_y = wwin->frame_y;
656 if (!scr->selected_windows){
657 drawTransparentFrame(wwin, src_x+lpr->ox, src_y+lpr->oy, w, h);
659 XUngrabServer(dpy);
660 XSync(dpy, False);
661 wusleep(10000);
662 XGrabServer(dpy);
663 printf("called\n");
664 if (!scr->selected_windows){
665 drawTransparentFrame(wwin, src_x+lpr->ox, src_y+lpr->oy, w, h);
667 /* reset timer */
668 if(scr->keymove_tick)
669 WMAddTimerHandler(15000,(WMCallback*)_keyloop, lpr);
672 #endif
673 #define _KS 20;
676 wKeyboardMoveResizeWindow(WWindow *wwin)
678 WScreen *scr = wwin->screen_ptr;
679 Window root = scr->root_win;
680 XEvent event;
681 int w = wwin->frame->core->width;
682 int h = wwin->frame->core->height;
683 int scr_width = wwin->screen_ptr->scr_width;
684 int scr_height = wwin->screen_ptr->scr_height;
685 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
686 int src_x = wwin->frame_x;
687 int src_y = wwin->frame_y;
688 int done,off_x,off_y,ww,wh;
689 KeySym keysym=NoSymbol;
690 KeyCode shiftl,shiftr,ctrll,ctrlmode;
693 int timer;
694 _looper looper;
695 looper.wwin=wwin;
696 scr->keymove_tick=1;
697 WMAddTimerHandler(1000,(WMCallback*)_keyloop, &looper);
700 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
701 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
702 ctrll = XKeysymToKeycode(dpy, XK_Control_L);
703 ctrlmode=done=off_x=off_y=0;
705 XSync(dpy, False);
706 wusleep(10000);
707 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
709 if (!wwin->flags.selected) {
710 wUnselectWindows(scr);
712 XGrabServer(dpy);
713 if (!scr->selected_windows){
714 drawTransparentFrame(wwin, src_x, src_y, w, h);
715 mapPositionDisplay(wwin, src_x, src_y, w, h);
716 } else {
717 drawFrames(wwin,scr->selected_windows,0,0,0,0);
719 ww=w;
720 wh=h;
721 while(1) {
723 looper.ox=off_x;
724 looper.oy=off_y;
726 WMMaskEvent(dpy, KeyPressMask | ButtonReleaseMask
727 | ButtonPressMask | ExposureMask, &event);
728 if (!scr->selected_windows){
729 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
731 else {
732 drawFrames(wwin,scr->selected_windows,off_x,off_y,0,0);
734 if(ctrlmode)
735 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
736 switch (event.type) {
737 case KeyPress:
738 if (event.xkey.state & ControlMask){
739 ctrlmode=1;
740 wUnselectWindows(scr);
742 else {
743 ctrlmode=0;
745 if (event.xkey.keycode == shiftl || event.xkey.keycode == shiftr){
746 if(ctrlmode)
747 cycleGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh, 0);
748 else
749 cyclePositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
751 else {
752 keysym = XLookupKeysym(&event.xkey, 0);
753 switch(keysym){
754 case XK_Return:
755 done=2;
756 break;
757 case XK_Escape:
758 done=1;
759 break;
760 case XK_Up:
761 case XK_KP_Up:
762 case XK_k:
763 if (ctrlmode){
764 h-=_KS;
766 else off_y-=_KS;
767 break;
768 case XK_Down:
769 case XK_KP_Down:
770 case XK_j:
771 if (ctrlmode){
772 h+=_KS;
774 else off_y+=_KS;
775 break;
776 case XK_Left:
777 case XK_KP_Left:
778 case XK_h:
779 if (ctrlmode){
780 w-=_KS;
782 else off_x-=_KS;
783 break;
784 case XK_Right:
785 case XK_KP_Right:
786 case XK_l:
787 if (ctrlmode){
788 w+=_KS;
790 else off_x+=_KS;
791 break;
793 ww=w;wh=h;
794 wh-=vert_border;
795 wWindowConstrainSize(wwin, &ww, &wh);
796 wh+=vert_border;
798 if (wPreferences.ws_cycle){
799 if (src_x + off_x + wwin->frame->core->width < 20){
800 if(!scr->current_workspace) {
801 wWorkspaceChange(scr, scr->workspace_count-1);
803 else wWorkspaceChange(scr, scr->current_workspace-1);
804 off_x += scr_width;
806 else if (src_x + off_x + 20 > scr_width){
807 if(scr->current_workspace == scr->workspace_count-1) {
808 wWorkspaceChange(scr, 0);
810 else wWorkspaceChange(scr, scr->current_workspace+1);
811 off_x -= scr_width;
814 else {
815 if (src_x + off_x + wwin->frame->core->width < 20)
816 off_x = 20 - wwin->frame->core->width - src_x;
817 else if (src_x + off_x + 20 > scr_width)
818 off_x = scr_width - 20 - src_x;
821 if (src_y + off_y + wwin->frame->core->height < 20)
822 off_y = 20 - wwin->frame->core->height - src_y;
823 else if (src_y + off_y + 20 > scr_height)
824 off_y = scr_height - 20 - src_y;
827 break;
828 case ButtonPress:
829 case ButtonRelease:
830 done=1;
831 break;
832 default:
833 WMHandleEvent(&event);
834 break;
837 XUngrabServer(dpy);
838 WMHandleEvent(&event);
839 XSync(dpy, False);
840 XGrabServer(dpy);
841 * */
842 if (!scr->selected_windows){
843 if(ctrlmode){
844 unmapPositionDisplay(wwin);
845 mapGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
847 else {
848 unmapGeometryDisplay(wwin);
849 mapPositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
851 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
853 else {
854 drawFrames(wwin,scr->selected_windows,off_x,off_y,0,0);
856 if(ctrlmode){
857 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
859 else
860 showPosition(wwin, src_x+off_x, src_y+off_y);
861 /**/
863 if(done){
864 scr->keymove_tick=0;
866 WMDeleteTimerWithClientData(&looper);
868 if (!scr->selected_windows){
869 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
871 else {
872 drawFrames(wwin,scr->selected_windows,off_x,off_y,0,0);
874 if(ctrlmode){
875 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
876 unmapGeometryDisplay(wwin);
878 else
879 unmapPositionDisplay(wwin);
880 XUngrabKeyboard(dpy, CurrentTime);
881 XUngrabServer(dpy);
882 if(done==2){
883 if (!scr->selected_windows){
884 wWindowConfigure(wwin, src_x+off_x, src_y+off_y, ww, wh - vert_border);
885 wWindowSynthConfigureNotify(wwin);
887 else {
888 LinkedList *list;
889 list=scr->selected_windows;
890 doWindowMove(wwin,0,0,scr->selected_windows,off_x,off_y,0,0);
891 while (list) {
892 wWindowSynthConfigureNotify(list->head);
893 list = list->tail;
896 wWindowChangeWorkspace(wwin, scr->current_workspace);
897 wSetFocusTo(scr, wwin);
899 return 1;
906 wMouseMoveWindow(WWindow *wwin, XEvent *ev)
908 WScreen *scr = wwin->screen_ptr;
909 XEvent event;
910 Window root = scr->root_win;
911 KeyCode shiftl, shiftr, tab;
912 int w = wwin->frame->core->width;
913 int h = wwin->frame->core->height;
914 int x = wwin->frame_x;
915 int y = wwin->frame_y;
916 int ox, oy, orig_x, orig_y;
917 int off_x, off_y;
918 short count = 0; /* for automatic workspace creation */
919 int started = 0;
920 int warped = 0;
921 /* This needs not to change while moving, else bad things can happen */
922 int opaque_move = wPreferences.opaque_move;
923 int XOffset, YOffset, origDragX, origDragY;
924 int grid = 0;
926 origDragX = wwin->frame_x;
927 origDragY = wwin->frame_y;
928 XOffset = origDragX - ev->xbutton.x_root;
929 YOffset = origDragY - ev->xbutton.y_root;
931 if (!wwin->flags.selected) {
932 /* this window is not selected, unselect others and move only wwin */
933 wUnselectWindows(scr);
935 orig_x = ox = ev->xbutton.x_root;
936 orig_y = oy = ev->xbutton.y_root;
937 off_x = x; off_y = y;
938 checkEdgeResistance(wwin, &off_x, &off_y, 0, 0);
939 off_x = (off_x-x); off_y = (off_y-y);
940 #ifdef DEBUG
941 puts("Moving window");
942 #endif
943 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
944 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
945 tab = XKeysymToKeycode(dpy, XK_Tab);
946 while (1) {
947 if (warped) {
948 int junk;
949 Window junkw;
951 /* XWarpPointer() doesn't seem to generate Motion events, so
952 we've got to simulate them */
953 printf("warp\n");
954 XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
955 &event.xmotion.y_root, &junk, &junk,
956 (unsigned *) &junk);
957 } else {
958 Window win;
960 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
961 | ButtonReleaseMask | ButtonPressMask | ExposureMask, &event);
963 if (event.type == MotionNotify) {
964 /* compress MotionNotify events */
965 win = event.xmotion.window;
966 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
969 switch (event.type) {
970 case KeyPress:
971 if (scr->selected_windows)
972 break;
973 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
974 && started) {
975 if (!opaque_move)
976 drawFrames(wwin, scr->selected_windows,
977 ox - orig_x, oy - orig_y, off_x, off_y);
979 cyclePositionDisplay(wwin, x, y, w, h);
981 if (!opaque_move) {
982 drawFrames(wwin, scr->selected_windows,
983 ox - orig_x, oy - orig_y, off_x, off_y);
985 showPosition(wwin, x, y);
987 if (event.xkey.keycode == tab) {
988 grid = !grid;
990 break;
992 case MotionNotify:
993 if (started) {
994 if (grid) {
995 event.xmotion.x_root = (event.xmotion.x_root/10)*10;
996 event.xmotion.y_root = (event.xmotion.y_root/10)*10;
998 showPosition(wwin, x, y);
1000 if (!opaque_move) {
1001 drawFrames(wwin, scr->selected_windows,
1002 ox-orig_x, oy-orig_y, off_x, off_y);
1003 } else {
1004 doWindowMove(wwin, event.xmotion.x_root + XOffset,
1005 event.xmotion.y_root + YOffset,
1006 scr->selected_windows,
1007 event.xmotion.x_root - ox,
1008 event.xmotion.y_root - oy,
1009 off_x, off_y);
1012 x = event.xmotion.x_root + XOffset;
1013 y = event.xmotion.y_root + YOffset;
1015 checkEdgeResistance(wwin, &x, &y, off_x, off_y);
1017 if (!scr->selected_windows) {
1018 if (wPreferences.move_display == WDIS_FRAME_CENTER)
1019 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
1021 if (!warped && !wPreferences.no_autowrap) {
1022 if (event.xmotion.x_root <= 1) {
1023 if (scr->current_workspace > 0) {
1024 crossWorkspace(scr, wwin, opaque_move,
1025 scr->current_workspace-1, True);
1026 warped = 1;
1027 count = 0;
1028 } else if (scr->current_workspace == 0
1029 && wPreferences.ws_cycle) {
1030 crossWorkspace(scr, wwin, opaque_move,
1031 scr->workspace_count-1, True);
1032 warped = 1;
1033 count = 0;
1035 } else if (event.xmotion.x_root >= scr->scr_width - 2) {
1037 if (scr->current_workspace == scr->workspace_count-1) {
1038 if ((!wPreferences.ws_advance && wPreferences.ws_cycle)
1039 || (scr->workspace_count == MAX_WORKSPACES)) {
1040 crossWorkspace(scr, wwin, opaque_move, 0, False);
1041 warped = 1;
1042 count = 0;
1044 /* if user insists on trying to go to next
1045 workspace even when it's already the last,
1046 create a new one */
1047 else if ((ox == event.xmotion.x_root)
1048 && wPreferences.ws_advance) {
1050 /* detect user "rubbing" the window
1051 against the edge */
1052 if (count > 0
1053 && oy - event.xmotion.y_root > MOVE_THRESHOLD)
1054 count = -(count + 1);
1055 else if (count <= 0
1056 && event.xmotion.y_root - oy > MOVE_THRESHOLD)
1057 count = -count + 1;
1059 /* create a new workspace */
1060 if (abs(count) > 2) {
1061 /* go to next workspace */
1062 wWorkspaceNew(scr);
1064 crossWorkspace(scr, wwin, opaque_move,
1065 scr->current_workspace+1, False);
1066 warped = 1;
1067 count = 0;
1069 } else if (scr->current_workspace < scr->workspace_count) {
1071 /* go to next workspace */
1072 crossWorkspace(scr, wwin, opaque_move,
1073 scr->current_workspace+1, False);
1074 warped = 1;
1075 count = 0;
1077 } else {
1078 count = 0;
1080 } else {
1081 warped = 0;
1083 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
1084 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1085 XChangeActivePointerGrab(dpy, ButtonMotionMask
1086 | ButtonReleaseMask | ButtonPressMask,
1087 wCursor[WCUR_MOVE], CurrentTime);
1088 started = 1;
1089 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
1090 CurrentTime);
1091 event.xmotion.x_root = orig_x;
1092 event.xmotion.y_root = orig_y;
1094 if (!scr->selected_windows)
1095 mapPositionDisplay(wwin, x, y, w, h);
1097 if (!opaque_move)
1098 XGrabServer(dpy);
1100 ox = event.xmotion.x_root;
1101 oy = event.xmotion.y_root;
1103 if (started && !opaque_move)
1104 drawFrames(wwin, scr->selected_windows, ox - orig_x, oy - orig_y, off_x, off_y);
1106 showPosition(wwin, x, y);
1107 break;
1109 case ButtonPress:
1110 break;
1112 case ButtonRelease:
1113 if (event.xbutton.button != ev->xbutton.button)
1114 break;
1116 if (started) {
1117 if (!opaque_move) {
1118 drawFrames(wwin, scr->selected_windows,
1119 ox - orig_x, oy - orig_y, off_x, off_y);
1120 XSync(dpy, 0);
1121 doWindowMove(wwin, event.xmotion.x_root + XOffset,
1122 event.xmotion.y_root + YOffset,
1123 scr->selected_windows,
1124 ox - orig_x, oy - orig_y,
1125 off_x, off_y);
1127 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
1128 wWindowSynthConfigureNotify(wwin);
1129 #endif
1131 XUngrabKeyboard(dpy, CurrentTime);
1132 XUngrabServer(dpy);
1133 if (!opaque_move) {
1134 wWindowChangeWorkspace(wwin, scr->current_workspace);
1135 wSetFocusTo(scr, wwin);
1137 showPosition(wwin, x, y);
1138 if (!scr->selected_windows) {
1139 /* get rid of the geometry window */
1140 unmapPositionDisplay(wwin);
1143 #ifdef DEBUG
1144 puts("End move window");
1145 #endif
1146 return started;
1148 default:
1149 if (started && !opaque_move) {
1150 drawFrames(wwin, scr->selected_windows, ox - orig_x, oy - orig_y, off_x, off_y);
1151 XUngrabServer(dpy);
1152 WMHandleEvent(&event);
1153 XSync(dpy, False);
1154 XGrabServer(dpy);
1155 drawFrames(wwin, scr->selected_windows, ox - orig_x, oy - orig_y, off_x, off_y);
1156 } else {
1157 WMHandleEvent(&event);
1159 break;
1162 return 0;
1166 #define RESIZEBAR 1
1167 #define HCONSTRAIN 2
1169 static int
1170 getResizeDirection(WWindow *wwin, int x, int y, int dx, int dy,
1171 int flags)
1173 int w = wwin->frame->core->width - 1;
1174 int cw = wwin->frame->resizebar_corner_width;
1175 int dir;
1177 /* if not resizing through the resizebar */
1178 if (!(flags & RESIZEBAR)) {
1179 int xdir = (abs(x) < (wwin->client.width/2)) ? LEFT : RIGHT;
1180 int ydir = (abs(y) < (wwin->client.height/2)) ? UP : DOWN;
1181 if (abs(dx) < 2 || abs(dy) < 2) {
1182 if (abs(dy) > abs(dx))
1183 xdir = 0;
1184 else
1185 ydir = 0;
1187 return (xdir | ydir);
1190 /* window is too narrow. allow diagonal resize */
1191 if (cw * 2 >= w) {
1192 int ydir;
1194 if (flags & HCONSTRAIN)
1195 ydir = 0;
1196 else
1197 ydir = DOWN;
1198 if (x < cw)
1199 return (LEFT | ydir);
1200 else
1201 return (RIGHT | ydir);
1203 /* vertical resize */
1204 if ((x > cw) && (x < w - cw))
1205 return DOWN;
1207 if (x < cw)
1208 dir = LEFT;
1209 else
1210 dir = RIGHT;
1212 if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
1213 dir |= DOWN;
1215 return dir;
1219 void
1220 wMouseResizeWindow(WWindow *wwin, XEvent *ev)
1222 XEvent event;
1223 WScreen *scr = wwin->screen_ptr;
1224 Window root = scr->root_win;
1225 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1226 int fw = wwin->frame->core->width;
1227 int fh = wwin->frame->core->height;
1228 int fx = wwin->frame_x;
1229 int fy = wwin->frame_y;
1230 int is_resizebar = (wwin->frame->resizebar
1231 && ev->xany.window==wwin->frame->resizebar->window);
1232 int orig_x, orig_y;
1233 int started;
1234 int dw, dh;
1235 int rw = fw, rh = fh;
1236 int rx1, ry1, rx2, ry2;
1237 int res = 0;
1238 KeyCode shiftl, shiftr;
1239 int h = 0;
1240 int orig_fx = fx;
1241 int orig_fy = fy;
1242 int orig_fw = fw;
1243 int orig_fh = fh;
1245 if (wwin->flags.shaded) {
1246 wwarning("internal error: tryein");
1247 return;
1249 orig_x = ev->xbutton.x_root;
1250 orig_y = ev->xbutton.y_root;
1252 started = 0;
1253 #ifdef DEBUG
1254 puts("Resizing window");
1255 #endif
1257 wUnselectWindows(scr);
1258 rx1 = fx;
1259 rx2 = fx + fw - 1;
1260 ry1 = fy;
1261 ry2 = fy + fh - 1;
1262 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1263 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1264 if (!WFLAGP(wwin, no_titlebar))
1265 h = wwin->screen_ptr->title_font->height + TITLEBAR_EXTRA_HEIGHT;
1266 else
1267 h = 0;
1268 while (1) {
1269 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask | ButtonReleaseMask
1270 | ButtonPressMask | ExposureMask, &event);
1271 switch (event.type) {
1272 case KeyPress:
1273 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1274 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1275 && started) {
1276 drawTransparentFrame(wwin, fx, fy, fw, fh);
1277 cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
1278 drawTransparentFrame(wwin, fx, fy, fw, fh);
1280 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1281 break;
1283 case MotionNotify:
1284 if (started) {
1285 dw = 0;
1286 dh = 0;
1288 orig_fx = fx;
1289 orig_fy = fy;
1290 orig_fw = fw;
1291 orig_fh = fh;
1293 if (res & LEFT)
1294 dw = orig_x - event.xmotion.x_root;
1295 else if (res & RIGHT)
1296 dw = event.xmotion.x_root - orig_x;
1297 if (res & UP)
1298 dh = orig_y - event.xmotion.y_root;
1299 else if (res & DOWN)
1300 dh = event.xmotion.y_root - orig_y;
1302 orig_x = event.xmotion.x_root;
1303 orig_y = event.xmotion.y_root;
1305 rw += dw;
1306 rh += dh;
1307 fw = rw;
1308 fh = rh - vert_border;
1309 wWindowConstrainSize(wwin, &fw, &fh);
1310 fh += vert_border;
1311 if (res & LEFT)
1312 fx = rx2 - fw + 1;
1313 else if (res & RIGHT)
1314 fx = rx1;
1315 if (res & UP)
1316 fy = ry2 - fh + 1;
1317 else if (res & DOWN)
1318 fy = ry1;
1319 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
1320 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1321 int tx, ty;
1322 Window junkw;
1323 int flags;
1325 XTranslateCoordinates(dpy, root, wwin->frame->core->window,
1326 orig_x, orig_y, &tx, &ty, &junkw);
1328 /* check if resizing through resizebar */
1329 if (is_resizebar)
1330 flags = RESIZEBAR;
1331 else
1332 flags = 0;
1334 if (is_resizebar && ((ev->xbutton.state & ShiftMask)
1335 || abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
1336 flags |= HCONSTRAIN;
1338 res = getResizeDirection(wwin, tx, ty,
1339 orig_x - event.xmotion.x_root,
1340 orig_y - event.xmotion.y_root, flags);
1342 XChangeActivePointerGrab(dpy, ButtonMotionMask
1343 | ButtonReleaseMask | ButtonPressMask,
1344 wCursor[WCUR_RESIZE], CurrentTime);
1345 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
1346 CurrentTime);
1348 XGrabServer(dpy);
1350 /* Draw the resize frame for the first time. */
1351 mapGeometryDisplay(wwin, fx, fy, fw, fh);
1353 drawTransparentFrame(wwin, fx, fy, fw, fh);
1355 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1357 started = 1;
1359 if (started) {
1360 if (wPreferences.size_display == WDIS_FRAME_CENTER) {
1361 drawTransparentFrame(wwin, orig_fx, orig_fy,
1362 orig_fw, orig_fh);
1363 moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
1364 drawTransparentFrame(wwin, fx, fy, fw, fh);
1365 } else {
1366 drawTransparentFrame(wwin, orig_fx, orig_fy,
1367 orig_fw, orig_fh);
1368 drawTransparentFrame(wwin, fx, fy, fw, fh);
1370 if (fh != orig_fh || fw != orig_fw) {
1371 if (wPreferences.size_display == WDIS_NEW) {
1372 showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw,
1373 orig_fy + orig_fh, res);
1375 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1378 break;
1380 case ButtonPress:
1381 break;
1383 case ButtonRelease:
1384 if (event.xbutton.button != ev->xbutton.button)
1385 break;
1387 if (started) {
1388 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1390 drawTransparentFrame(wwin, fx, fy, fw, fh);
1392 XUngrabKeyboard(dpy, CurrentTime);
1393 unmapGeometryDisplay(wwin);
1394 XUngrabServer(dpy);
1395 wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
1397 #ifdef DEBUG
1398 puts("End resize window");
1399 #endif
1400 return;
1402 default:
1403 WMHandleEvent(&event);
1408 #undef LEFT
1409 #undef RIGHT
1410 #undef HORIZONTAL
1411 #undef UP
1412 #undef DOWN
1413 #undef VERTICAL
1414 #undef HCONSTRAIN
1415 #undef RESIZEBAR
1417 void
1418 wUnselectWindows(WScreen *scr)
1420 WWindow *wwin;
1422 while (scr->selected_windows) {
1423 wwin = scr->selected_windows->head;
1424 if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
1425 wIconSelect(wwin->icon);
1427 wSelectWindow(wwin, False);
1431 #ifndef LITE
1432 static void
1433 selectWindowsInside(WScreen *scr, int x1, int y1, int x2, int y2)
1435 WWindow *tmpw;
1437 /* select the windows and put them in the selected window list */
1438 tmpw = scr->focused_window;
1439 while (tmpw != NULL) {
1440 if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
1441 if ((tmpw->frame->workspace == scr->current_workspace
1442 || IS_OMNIPRESENT(tmpw))
1443 && (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1)
1444 && (tmpw->frame->core->width + tmpw->frame_x <= x2)
1445 && (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
1446 wSelectWindow(tmpw, True);
1449 tmpw = tmpw->prev;
1454 void
1455 wSelectWindows(WScreen *scr, XEvent *ev)
1457 XEvent event;
1458 Window root = scr->root_win;
1459 GC gc = scr->frame_gc;
1460 int xp = ev->xbutton.x_root;
1461 int yp = ev->xbutton.y_root;
1462 int w = 0, h = 0;
1463 int x = xp, y = yp;
1465 #ifdef DEBUG
1466 puts("Selecting windows");
1467 #endif
1468 if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
1469 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
1470 GrabModeAsync, None, wCursor[WCUR_DEFAULT],
1471 CurrentTime) != Success) {
1472 return;
1474 XGrabServer(dpy);
1476 wUnselectWindows(scr);
1478 XDrawRectangle(dpy, root, gc, xp, yp, w, h);
1479 while (1) {
1480 WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask
1481 | ButtonPressMask, &event);
1483 switch (event.type) {
1484 case MotionNotify:
1485 XDrawRectangle(dpy, root, gc, x, y, w, h);
1486 x = event.xmotion.x_root;
1487 if (x < xp) {
1488 w = xp - x;
1489 } else {
1490 w = x - xp;
1491 x = xp;
1493 y = event.xmotion.y_root;
1494 if (y < yp) {
1495 h = yp - y;
1496 } else {
1497 h = y - yp;
1498 y = yp;
1500 XDrawRectangle(dpy, root, gc, x, y, w, h);
1501 break;
1503 case ButtonPress:
1504 break;
1506 case ButtonRelease:
1507 if (event.xbutton.button != ev->xbutton.button)
1508 break;
1510 XDrawRectangle(dpy, root, gc, x, y, w, h);
1511 XUngrabServer(dpy);
1512 XUngrabPointer(dpy, CurrentTime);
1513 selectWindowsInside(scr, x, y, x + w, y + h);
1514 #ifdef DEBUG
1515 puts("End window selection");
1516 #endif
1517 return;
1519 default:
1520 WMHandleEvent(&event);
1524 #endif /* !LITE */
1526 void
1527 InteractivePlaceWindow(WWindow *wwin, int *x_ret, int *y_ret,
1528 unsigned width, unsigned height)
1530 WScreen *scr = wwin->screen_ptr;
1531 Window root = scr->root_win;
1532 int x, y, h = 0;
1533 XEvent event;
1534 KeyCode shiftl, shiftr;
1535 Window junkw;
1536 int junk;
1538 if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
1539 GrabModeAsync, GrabModeAsync, None,
1540 wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
1541 *x_ret = 0;
1542 *y_ret = 0;
1543 return;
1545 if (!WFLAGP(wwin, no_titlebar)) {
1546 h = scr->title_font->height + TITLEBAR_EXTRA_HEIGHT;
1547 height += h;
1549 if (!WFLAGP(wwin, no_resizebar)) {
1550 height += RESIZEBAR_HEIGHT;
1552 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1553 XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk,
1554 (unsigned *) &junk);
1555 mapPositionDisplay(wwin, x - width/2, y - h/2, width, height);
1557 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1559 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1560 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1561 while (1) {
1562 WMMaskEvent(dpy, PointerMotionMask|ButtonPressMask|ExposureMask|KeyPressMask,
1563 &event);
1564 switch (event.type) {
1565 case KeyPress:
1566 if ((event.xkey.keycode == shiftl)
1567 || (event.xkey.keycode == shiftr)) {
1568 drawTransparentFrame(wwin,
1569 x - width/2, y - h/2, width, height);
1570 cyclePositionDisplay(wwin,
1571 x - width/2, y - h/2, width, height);
1572 drawTransparentFrame(wwin,
1573 x - width/2, y - h/2, width, height);
1575 break;
1577 case MotionNotify:
1578 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1580 x = event.xmotion.x_root;
1581 y = event.xmotion.y_root;
1583 if (wPreferences.move_display == WDIS_FRAME_CENTER)
1584 moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
1586 showPosition(wwin, x - width/2, y - h/2);
1588 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1590 break;
1592 case ButtonPress:
1593 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1594 XSync(dpy, 0);
1595 *x_ret = x - width/2;
1596 *y_ret = y - h/2;
1597 XUngrabPointer(dpy, CurrentTime);
1598 XUngrabKeyboard(dpy, CurrentTime);
1599 /* get rid of the geometry window */
1600 unmapPositionDisplay(wwin);
1601 return;
1603 default:
1604 WMHandleEvent(&event);
1605 break;