Code update for Window Maker version 0.50.0
[wmaker-crm.git] / src / moveres.c
blob58bc5859a78a3ab50012e83fd68a4997fe69b19c
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 while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
590 static void
591 crossWorkspace(WScreen *scr, WWindow *wwin, int opaque_move,
592 int new_workspace, int rewind)
594 /* do not let window be unmapped */
595 if (opaque_move) {
596 wwin->flags.changing_workspace = 1;
597 wWindowChangeWorkspace(wwin, new_workspace);
599 /* go to new workspace */
600 wWorkspaceChange(scr, new_workspace);
602 wwin->flags.changing_workspace = 0;
604 if (rewind)
605 XWarpPointer(dpy, None, None, 0, 0, 0, 0, scr->scr_width - 20, 0);
606 else
607 XWarpPointer(dpy, None, None, 0, 0, 0, 0, -(scr->scr_width - 20), 0);
609 flushMotion();
611 if (!opaque_move) {
612 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
613 |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
614 GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
620 *----------------------------------------------------------------------
621 * wMouseMoveWindow--
622 * Move the named window and the other selected ones (if any),
623 * interactively. Also shows the position of the window, if only one
624 * window is being moved.
625 * If the window is not on the selected window list, the selected
626 * windows are deselected.
627 * If shift is pressed during the operation, the position display
628 * is changed to another type.
630 * Returns:
631 * True if the window was moved, False otherwise.
633 * Side effects:
634 * The window(s) position is changed, and the client(s) are
635 * notified about that.
636 * The position display configuration may be changed.
637 *----------------------------------------------------------------------
640 #if 0
641 typedef struct _looper {
642 WWindow *wwin;
643 int x,y,w,h,ox,oy;
644 } _looper;
646 void
647 _keyloop(_looper *lpr){
648 WWindow *wwin = lpr->wwin;
649 WScreen *scr = wwin->screen_ptr;
650 int w = wwin->frame->core->width;
651 int h = wwin->frame->core->height;
652 int src_x = wwin->frame_x;
653 int src_y = wwin->frame_y;
655 if (!scr->selected_windows){
656 drawTransparentFrame(wwin, src_x+lpr->ox, src_y+lpr->oy, w, h);
658 XUngrabServer(dpy);
659 XSync(dpy, False);
660 usleep(10000);
661 XGrabServer(dpy);
662 printf("called\n");
663 if (!scr->selected_windows){
664 drawTransparentFrame(wwin, src_x+lpr->ox, src_y+lpr->oy, w, h);
666 /* reset timer */
667 if(scr->keymove_tick)
668 WMAddTimerHandler(15000,(WMCallback*)_keyloop, lpr);
671 #endif
672 #define _KS 20;
675 wKeyboardMoveResizeWindow(WWindow *wwin)
677 WScreen *scr = wwin->screen_ptr;
678 Window root = scr->root_win;
679 XEvent event;
680 int w = wwin->frame->core->width;
681 int h = wwin->frame->core->height;
682 int scr_width = wwin->screen_ptr->scr_width;
683 int scr_height = wwin->screen_ptr->scr_height;
684 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
685 int src_x = wwin->frame_x;
686 int src_y = wwin->frame_y;
687 int done,off_x,off_y,ww,wh;
688 KeySym keysym=NoSymbol;
689 KeyCode shiftl,shiftr,ctrll,ctrlmode;
692 int timer;
693 _looper looper;
694 looper.wwin=wwin;
695 scr->keymove_tick=1;
696 WMAddTimerHandler(1000,(WMCallback*)_keyloop, &looper);
699 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
700 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
701 ctrll = XKeysymToKeycode(dpy, XK_Control_L);
702 ctrlmode=done=off_x=off_y=0;
704 XSync(dpy, False);
705 usleep(10000);
706 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
708 if (!wwin->flags.selected) {
709 wUnselectWindows(scr);
711 XGrabServer(dpy);
712 if (!scr->selected_windows){
713 drawTransparentFrame(wwin, src_x, src_y, w, h);
714 mapPositionDisplay(wwin, src_x, src_y, w, h);
715 } else {
716 drawFrames(wwin,scr->selected_windows,0,0,0,0);
718 ww=w;
719 wh=h;
720 while(1) {
722 looper.ox=off_x;
723 looper.oy=off_y;
725 WMMaskEvent(dpy, KeyPressMask | ButtonReleaseMask
726 | ButtonPressMask | ExposureMask, &event);
727 if (!scr->selected_windows){
728 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
730 else {
731 drawFrames(wwin,scr->selected_windows,off_x,off_y,0,0);
733 if(ctrlmode)
734 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
735 switch (event.type) {
736 case KeyPress:
737 if (event.xkey.state & ControlMask){
738 ctrlmode=1;
739 wUnselectWindows(scr);
741 else {
742 ctrlmode=0;
744 if (event.xkey.keycode == shiftl || event.xkey.keycode == shiftr){
745 if(ctrlmode)
746 cycleGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh, 0);
747 else
748 cyclePositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
750 else {
751 keysym = XLookupKeysym(&event.xkey, 0);
752 switch(keysym){
753 case XK_Return:
754 done=2;
755 break;
756 case XK_Escape:
757 done=1;
758 break;
759 case XK_Up:
760 case XK_KP_Up:
761 case XK_k:
762 if (ctrlmode){
763 h-=_KS;
765 else off_y-=_KS;
766 break;
767 case XK_Down:
768 case XK_KP_Down:
769 case XK_j:
770 if (ctrlmode){
771 h+=_KS;
773 else off_y+=_KS;
774 break;
775 case XK_Left:
776 case XK_KP_Left:
777 case XK_h:
778 if (ctrlmode){
779 w-=_KS;
781 else off_x-=_KS;
782 break;
783 case XK_Right:
784 case XK_KP_Right:
785 case XK_l:
786 if (ctrlmode){
787 w+=_KS;
789 else off_x+=_KS;
790 break;
792 ww=w;wh=h;
793 wh-=vert_border;
794 wWindowConstrainSize(wwin, &ww, &wh);
795 wh+=vert_border;
797 if (wPreferences.ws_cycle){
798 if (src_x + off_x + wwin->frame->core->width < 20){
799 if(!scr->current_workspace) {
800 wWorkspaceChange(scr, scr->workspace_count-1);
802 else wWorkspaceChange(scr, scr->current_workspace-1);
803 off_x += scr_width;
805 else if (src_x + off_x + 20 > scr_width){
806 if(scr->current_workspace == scr->workspace_count-1) {
807 wWorkspaceChange(scr, 0);
809 else wWorkspaceChange(scr, scr->current_workspace+1);
810 off_x -= scr_width;
813 else {
814 if (src_x + off_x + wwin->frame->core->width < 20)
815 off_x = 20 - wwin->frame->core->width - src_x;
816 else if (src_x + off_x + 20 > scr_width)
817 off_x = scr_width - 20 - src_x;
820 if (src_y + off_y + wwin->frame->core->height < 20)
821 off_y = 20 - wwin->frame->core->height - src_y;
822 else if (src_y + off_y + 20 > scr_height)
823 off_y = scr_height - 20 - src_y;
826 break;
827 case ButtonPress:
828 case ButtonRelease:
829 done=1;
830 break;
831 default:
834 XUngrabServer(dpy);
835 WMHandleEvent(&event);
836 XSync(dpy, False);
837 XGrabServer(dpy);
838 * */
839 if (!scr->selected_windows){
840 if(ctrlmode){
841 unmapPositionDisplay(wwin);
842 mapGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
844 else {
845 unmapGeometryDisplay(wwin);
846 mapPositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
848 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
850 else {
851 drawFrames(wwin,scr->selected_windows,off_x,off_y,0,0);
853 if(ctrlmode){
854 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
856 else
857 showPosition(wwin, src_x+off_x, src_y+off_y);
858 /**/
860 if(done){
861 scr->keymove_tick=0;
863 WMDeleteTimerWithClientData(&looper);
865 if (!scr->selected_windows){
866 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
868 else {
869 drawFrames(wwin,scr->selected_windows,off_x,off_y,0,0);
871 if(ctrlmode){
872 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
873 unmapGeometryDisplay(wwin);
875 else
876 unmapPositionDisplay(wwin);
877 XUngrabKeyboard(dpy, CurrentTime);
878 XUngrabServer(dpy);
879 if(done==2){
880 if (!scr->selected_windows){
881 wWindowConfigure(wwin, src_x+off_x, src_y+off_y, ww, wh - vert_border);
882 wWindowSynthConfigureNotify(wwin);
884 else {
885 LinkedList *list;
886 list=scr->selected_windows;
887 doWindowMove(wwin,0,0,scr->selected_windows,off_x,off_y,0,0);
888 while (list) {
889 wWindowSynthConfigureNotify(list->head);
890 list = list->tail;
893 wWindowChangeWorkspace(wwin, scr->current_workspace);
894 wSetFocusTo(scr, wwin);
896 return 1;
903 wMouseMoveWindow(WWindow *wwin, XEvent *ev)
905 WScreen *scr = wwin->screen_ptr;
906 XEvent event;
907 Window root = scr->root_win;
908 KeyCode shiftl, shiftr, tab;
909 int w = wwin->frame->core->width;
910 int h = wwin->frame->core->height;
911 int x = wwin->frame_x;
912 int y = wwin->frame_y;
913 int ox, oy, orig_x, orig_y;
914 int off_x, off_y;
915 short count = 0; /* for automatic workspace creation */
916 int started = 0;
917 int warped = 0;
918 /* This needs not to change while moving, else bad things can happen */
919 int opaque_move = wPreferences.opaque_move;
920 int XOffset, YOffset, origDragX, origDragY;
921 int grid = 0;
923 origDragX = wwin->frame_x;
924 origDragY = wwin->frame_y;
925 XOffset = origDragX - ev->xbutton.x_root;
926 YOffset = origDragY - ev->xbutton.y_root;
928 if (!wwin->flags.selected) {
929 /* this window is not selected, unselect others and move only wwin */
930 wUnselectWindows(scr);
932 orig_x = ox = ev->xbutton.x_root;
933 orig_y = oy = ev->xbutton.y_root;
934 off_x = x; off_y = y;
935 checkEdgeResistance(wwin, &off_x, &off_y, 0, 0);
936 off_x = (off_x-x); off_y = (off_y-y);
937 #ifdef DEBUG
938 puts("Moving window");
939 #endif
940 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
941 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
942 tab = XKeysymToKeycode(dpy, XK_Tab);
943 while (1) {
944 if (warped) {
945 int junk;
946 Window junkw;
948 /* XWarpPointer() doesn't seem to generate Motion events, so
949 we've got to simulate them */
950 printf("warp\n");
951 XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
952 &event.xmotion.y_root, &junk, &junk,
953 (unsigned *) &junk);
954 } else {
955 Window win;
957 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
958 | ButtonReleaseMask | ButtonPressMask | ExposureMask, &event);
960 if (event.type == MotionNotify) {
961 /* compress MotionNotify events */
962 win = event.xmotion.window;
963 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
966 switch (event.type) {
967 case KeyPress:
968 if (scr->selected_windows)
969 break;
970 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
971 && started) {
972 if (!opaque_move)
973 drawFrames(wwin, scr->selected_windows,
974 ox - orig_x, oy - orig_y, off_x, off_y);
976 cyclePositionDisplay(wwin, x, y, w, h);
978 if (!opaque_move) {
979 drawFrames(wwin, scr->selected_windows,
980 ox - orig_x, oy - orig_y, off_x, off_y);
982 showPosition(wwin, x, y);
984 if (event.xkey.keycode == tab) {
985 grid = !grid;
987 break;
989 case MotionNotify:
990 if (started) {
991 if (grid) {
992 event.xmotion.x_root = (event.xmotion.x_root/10)*10;
993 event.xmotion.y_root = (event.xmotion.y_root/10)*10;
995 showPosition(wwin, x, y);
997 if (!opaque_move) {
998 drawFrames(wwin, scr->selected_windows,
999 ox-orig_x, oy-orig_y, off_x, off_y);
1000 } else {
1001 doWindowMove(wwin, event.xmotion.x_root + XOffset,
1002 event.xmotion.y_root + YOffset,
1003 scr->selected_windows,
1004 event.xmotion.x_root - ox,
1005 event.xmotion.y_root - oy,
1006 off_x, off_y);
1009 x = event.xmotion.x_root + XOffset;
1010 y = event.xmotion.y_root + YOffset;
1012 checkEdgeResistance(wwin, &x, &y, off_x, off_y);
1014 if (!scr->selected_windows) {
1015 if (wPreferences.move_display == WDIS_FRAME_CENTER)
1016 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
1018 if (!warped && !wPreferences.no_autowrap) {
1019 if (event.xmotion.x_root <= 1) {
1020 if (scr->current_workspace > 0) {
1021 crossWorkspace(scr, wwin, opaque_move,
1022 scr->current_workspace-1, True);
1023 warped = 1;
1024 count = 0;
1025 } else if (scr->current_workspace == 0
1026 && wPreferences.ws_cycle) {
1027 crossWorkspace(scr, wwin, opaque_move,
1028 scr->workspace_count-1, True);
1029 warped = 1;
1030 count = 0;
1032 } else if (event.xmotion.x_root >= scr->scr_width - 2) {
1034 if (scr->current_workspace == scr->workspace_count-1) {
1035 if ((!wPreferences.ws_advance && wPreferences.ws_cycle)
1036 || (scr->workspace_count == MAX_WORKSPACES)) {
1037 crossWorkspace(scr, wwin, opaque_move, 0, False);
1038 warped = 1;
1039 count = 0;
1041 /* if user insists on trying to go to next
1042 workspace even when it's already the last,
1043 create a new one */
1044 else if ((ox == event.xmotion.x_root)
1045 && wPreferences.ws_advance) {
1047 /* detect user "rubbing" the window
1048 against the edge */
1049 if (count > 0
1050 && oy - event.xmotion.y_root > MOVE_THRESHOLD)
1051 count = -(count + 1);
1052 else if (count <= 0
1053 && event.xmotion.y_root - oy > MOVE_THRESHOLD)
1054 count = -count + 1;
1056 /* create a new workspace */
1057 if (abs(count) > 2) {
1058 /* go to next workspace */
1059 wWorkspaceNew(scr);
1061 crossWorkspace(scr, wwin, opaque_move,
1062 scr->current_workspace+1, False);
1063 warped = 1;
1064 count = 0;
1066 } else if (scr->current_workspace < scr->workspace_count) {
1068 /* go to next workspace */
1069 crossWorkspace(scr, wwin, opaque_move,
1070 scr->current_workspace+1, False);
1071 warped = 1;
1072 count = 0;
1074 } else {
1075 count = 0;
1077 } else {
1078 warped = 0;
1080 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
1081 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1082 XChangeActivePointerGrab(dpy, ButtonMotionMask
1083 | ButtonReleaseMask | ButtonPressMask,
1084 wCursor[WCUR_MOVE], CurrentTime);
1085 started = 1;
1086 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
1087 CurrentTime);
1088 event.xmotion.x_root = orig_x;
1089 event.xmotion.y_root = orig_y;
1091 if (!scr->selected_windows)
1092 mapPositionDisplay(wwin, x, y, w, h);
1094 if (!opaque_move)
1095 XGrabServer(dpy);
1097 ox = event.xmotion.x_root;
1098 oy = event.xmotion.y_root;
1100 if (started && !opaque_move)
1101 drawFrames(wwin, scr->selected_windows, ox - orig_x, oy - orig_y, off_x, off_y);
1103 showPosition(wwin, x, y);
1104 break;
1106 case ButtonPress:
1107 break;
1109 case ButtonRelease:
1110 if (event.xbutton.button != ev->xbutton.button)
1111 break;
1113 if (started) {
1114 if (!opaque_move) {
1115 drawFrames(wwin, scr->selected_windows,
1116 ox - orig_x, oy - orig_y, off_x, off_y);
1117 XSync(dpy, 0);
1118 doWindowMove(wwin, event.xmotion.x_root + XOffset,
1119 event.xmotion.y_root + YOffset,
1120 scr->selected_windows,
1121 ox - orig_x, oy - orig_y,
1122 off_x, off_y);
1124 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
1125 wWindowSynthConfigureNotify(wwin);
1126 #endif
1128 XUngrabKeyboard(dpy, CurrentTime);
1129 XUngrabServer(dpy);
1130 if (!opaque_move) {
1131 wWindowChangeWorkspace(wwin, scr->current_workspace);
1132 wSetFocusTo(scr, wwin);
1134 showPosition(wwin, x, y);
1135 if (!scr->selected_windows) {
1136 /* get rid of the geometry window */
1137 unmapPositionDisplay(wwin);
1140 #ifdef DEBUG
1141 puts("End move window");
1142 #endif
1143 return started;
1145 default:
1146 if (started && !opaque_move) {
1147 drawFrames(wwin, scr->selected_windows, ox - orig_x, oy - orig_y, off_x, off_y);
1148 XUngrabServer(dpy);
1149 WMHandleEvent(&event);
1150 XSync(dpy, False);
1151 XGrabServer(dpy);
1152 drawFrames(wwin, scr->selected_windows, ox - orig_x, oy - orig_y, off_x, off_y);
1153 } else {
1154 WMHandleEvent(&event);
1156 break;
1159 return 0;
1163 #define RESIZEBAR 1
1164 #define HCONSTRAIN 2
1166 static int
1167 getResizeDirection(WWindow *wwin, int x, int y, int dx, int dy,
1168 int flags)
1170 int w = wwin->frame->core->width - 1;
1171 int cw = wwin->frame->resizebar_corner_width;
1172 int dir;
1174 /* if not resizing through the resizebar */
1175 if (!(flags & RESIZEBAR)) {
1176 int xdir = (abs(x) < (wwin->client.width/2)) ? LEFT : RIGHT;
1177 int ydir = (abs(y) < (wwin->client.height/2)) ? UP : DOWN;
1178 if (abs(dx) < 2 || abs(dy) < 2) {
1179 if (abs(dy) > abs(dx))
1180 xdir = 0;
1181 else
1182 ydir = 0;
1184 return (xdir | ydir);
1187 /* window is too narrow. allow diagonal resize */
1188 if (cw * 2 >= w) {
1189 int ydir;
1191 if (flags & HCONSTRAIN)
1192 ydir = 0;
1193 else
1194 ydir = DOWN;
1195 if (x < cw)
1196 return (LEFT | ydir);
1197 else
1198 return (RIGHT | ydir);
1200 /* vertical resize */
1201 if ((x > cw) && (x < w - cw))
1202 return DOWN;
1204 if (x < cw)
1205 dir = LEFT;
1206 else
1207 dir = RIGHT;
1209 if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
1210 dir |= DOWN;
1212 return dir;
1216 void
1217 wMouseResizeWindow(WWindow *wwin, XEvent *ev)
1219 XEvent event;
1220 WScreen *scr = wwin->screen_ptr;
1221 Window root = scr->root_win;
1222 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1223 int fw = wwin->frame->core->width;
1224 int fh = wwin->frame->core->height;
1225 int fx = wwin->frame_x;
1226 int fy = wwin->frame_y;
1227 int is_resizebar = (wwin->frame->resizebar
1228 && ev->xany.window==wwin->frame->resizebar->window);
1229 int orig_x, orig_y;
1230 int started;
1231 int dw, dh;
1232 int rw = fw, rh = fh;
1233 int rx1, ry1, rx2, ry2;
1234 int res = 0;
1235 KeyCode shiftl, shiftr;
1236 int h = 0;
1237 int orig_fx = fx;
1238 int orig_fy = fy;
1239 int orig_fw = fw;
1240 int orig_fh = fh;
1242 if (wwin->flags.shaded) {
1243 wwarning("internal error: tryein");
1244 return;
1246 orig_x = ev->xbutton.x_root;
1247 orig_y = ev->xbutton.y_root;
1249 started = 0;
1250 #ifdef DEBUG
1251 puts("Resizing window");
1252 #endif
1254 wUnselectWindows(scr);
1255 rx1 = fx;
1256 rx2 = fx + fw - 1;
1257 ry1 = fy;
1258 ry2 = fy + fh - 1;
1259 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1260 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1261 if (!WFLAGP(wwin, no_titlebar))
1262 h = wwin->screen_ptr->title_font->height + TITLEBAR_EXTRA_HEIGHT;
1263 else
1264 h = 0;
1265 while (1) {
1266 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask | ButtonReleaseMask
1267 | ButtonPressMask | ExposureMask, &event);
1268 switch (event.type) {
1269 case KeyPress:
1270 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1271 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1272 && started) {
1273 drawTransparentFrame(wwin, fx, fy, fw, fh);
1274 cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
1275 drawTransparentFrame(wwin, fx, fy, fw, fh);
1277 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1278 break;
1280 case MotionNotify:
1281 if (started) {
1282 dw = 0;
1283 dh = 0;
1285 orig_fx = fx;
1286 orig_fy = fy;
1287 orig_fw = fw;
1288 orig_fh = fh;
1290 if (res & LEFT)
1291 dw = orig_x - event.xmotion.x_root;
1292 else if (res & RIGHT)
1293 dw = event.xmotion.x_root - orig_x;
1294 if (res & UP)
1295 dh = orig_y - event.xmotion.y_root;
1296 else if (res & DOWN)
1297 dh = event.xmotion.y_root - orig_y;
1299 orig_x = event.xmotion.x_root;
1300 orig_y = event.xmotion.y_root;
1302 rw += dw;
1303 rh += dh;
1304 fw = rw;
1305 fh = rh - vert_border;
1306 wWindowConstrainSize(wwin, &fw, &fh);
1307 fh += vert_border;
1308 if (res & LEFT)
1309 fx = rx2 - fw + 1;
1310 else if (res & RIGHT)
1311 fx = rx1;
1312 if (res & UP)
1313 fy = ry2 - fh + 1;
1314 else if (res & DOWN)
1315 fy = ry1;
1316 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
1317 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1318 int tx, ty;
1319 Window junkw;
1320 int flags;
1322 XTranslateCoordinates(dpy, root, wwin->frame->core->window,
1323 orig_x, orig_y, &tx, &ty, &junkw);
1325 /* check if resizing through resizebar */
1326 if (is_resizebar)
1327 flags = RESIZEBAR;
1328 else
1329 flags = 0;
1331 if (is_resizebar && ((ev->xbutton.state & ShiftMask)
1332 || abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
1333 flags |= HCONSTRAIN;
1335 res = getResizeDirection(wwin, tx, ty,
1336 orig_x - event.xmotion.x_root,
1337 orig_y - event.xmotion.y_root, flags);
1339 XChangeActivePointerGrab(dpy, ButtonMotionMask
1340 | ButtonReleaseMask | ButtonPressMask,
1341 wCursor[WCUR_RESIZE], CurrentTime);
1342 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
1343 CurrentTime);
1345 XGrabServer(dpy);
1347 /* Draw the resize frame for the first time. */
1348 mapGeometryDisplay(wwin, fx, fy, fw, fh);
1350 drawTransparentFrame(wwin, fx, fy, fw, fh);
1352 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1354 started = 1;
1356 if (started) {
1357 if (wPreferences.size_display == WDIS_FRAME_CENTER) {
1358 drawTransparentFrame(wwin, orig_fx, orig_fy,
1359 orig_fw, orig_fh);
1360 moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
1361 drawTransparentFrame(wwin, fx, fy, fw, fh);
1362 } else {
1363 drawTransparentFrame(wwin, orig_fx, orig_fy,
1364 orig_fw, orig_fh);
1365 drawTransparentFrame(wwin, fx, fy, fw, fh);
1367 if (fh != orig_fh || fw != orig_fw) {
1368 if (wPreferences.size_display == WDIS_NEW) {
1369 showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw,
1370 orig_fy + orig_fh, res);
1372 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1375 break;
1377 case ButtonPress:
1378 break;
1380 case ButtonRelease:
1381 if (event.xbutton.button != ev->xbutton.button)
1382 break;
1384 if (started) {
1385 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1387 drawTransparentFrame(wwin, fx, fy, fw, fh);
1389 XUngrabKeyboard(dpy, CurrentTime);
1390 unmapGeometryDisplay(wwin);
1391 XUngrabServer(dpy);
1392 wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
1394 #ifdef DEBUG
1395 puts("End resize window");
1396 #endif
1397 return;
1399 default:
1400 WMHandleEvent(&event);
1405 #undef LEFT
1406 #undef RIGHT
1407 #undef HORIZONTAL
1408 #undef UP
1409 #undef DOWN
1410 #undef VERTICAL
1411 #undef HCONSTRAIN
1412 #undef RESIZEBAR
1414 void
1415 wUnselectWindows(WScreen *scr)
1417 WWindow *wwin;
1419 while (scr->selected_windows) {
1420 wwin = scr->selected_windows->head;
1421 if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
1422 wIconSelect(wwin->icon);
1424 wSelectWindow(wwin, False);
1428 #ifndef LITE
1429 static void
1430 selectWindowsInside(WScreen *scr, int x1, int y1, int x2, int y2)
1432 WWindow *tmpw;
1434 /* select the windows and put them in the selected window list */
1435 tmpw = scr->focused_window;
1436 while (tmpw != NULL) {
1437 if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
1438 if ((tmpw->frame->workspace == scr->current_workspace
1439 || IS_OMNIPRESENT(tmpw))
1440 && (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1)
1441 && (tmpw->frame->core->width + tmpw->frame_x <= x2)
1442 && (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
1443 wSelectWindow(tmpw, True);
1446 tmpw = tmpw->prev;
1451 void
1452 wSelectWindows(WScreen *scr, XEvent *ev)
1454 XEvent event;
1455 Window root = scr->root_win;
1456 GC gc = scr->frame_gc;
1457 int xp = ev->xbutton.x_root;
1458 int yp = ev->xbutton.y_root;
1459 int w = 0, h = 0;
1460 int x = xp, y = yp;
1462 #ifdef DEBUG
1463 puts("Selecting windows");
1464 #endif
1465 if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
1466 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
1467 GrabModeAsync, None, wCursor[WCUR_DEFAULT],
1468 CurrentTime) != Success) {
1469 return;
1471 XGrabServer(dpy);
1473 wUnselectWindows(scr);
1475 XDrawRectangle(dpy, root, gc, xp, yp, w, h);
1476 while (1) {
1477 WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask
1478 | ButtonPressMask, &event);
1480 switch (event.type) {
1481 case MotionNotify:
1482 XDrawRectangle(dpy, root, gc, x, y, w, h);
1483 x = event.xmotion.x_root;
1484 if (x < xp) {
1485 w = xp - x;
1486 } else {
1487 w = x - xp;
1488 x = xp;
1490 y = event.xmotion.y_root;
1491 if (y < yp) {
1492 h = yp - y;
1493 } else {
1494 h = y - yp;
1495 y = yp;
1497 XDrawRectangle(dpy, root, gc, x, y, w, h);
1498 break;
1500 case ButtonPress:
1501 break;
1503 case ButtonRelease:
1504 if (event.xbutton.button != ev->xbutton.button)
1505 break;
1507 XDrawRectangle(dpy, root, gc, x, y, w, h);
1508 XUngrabServer(dpy);
1509 XUngrabPointer(dpy, CurrentTime);
1510 selectWindowsInside(scr, x, y, x + w, y + h);
1511 #ifdef DEBUG
1512 puts("End window selection");
1513 #endif
1514 return;
1516 default:
1517 WMHandleEvent(&event);
1521 #endif /* !LITE */
1523 void
1524 InteractivePlaceWindow(WWindow *wwin, int *x_ret, int *y_ret,
1525 unsigned width, unsigned height)
1527 WScreen *scr = wwin->screen_ptr;
1528 Window root = scr->root_win;
1529 int x, y, h = 0;
1530 XEvent event;
1531 KeyCode shiftl, shiftr;
1532 Window junkw;
1533 int junk;
1535 if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
1536 GrabModeAsync, GrabModeAsync, None,
1537 wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
1538 *x_ret = 0;
1539 *y_ret = 0;
1540 return;
1542 if (!WFLAGP(wwin, no_titlebar)) {
1543 h = scr->title_font->height + TITLEBAR_EXTRA_HEIGHT;
1544 height += h;
1546 if (!WFLAGP(wwin, no_resizebar)) {
1547 height += RESIZEBAR_HEIGHT;
1549 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1550 XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk,
1551 (unsigned *) &junk);
1552 mapPositionDisplay(wwin, x - width/2, y - h/2, width, height);
1554 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1556 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1557 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1558 while (1) {
1559 WMMaskEvent(dpy, PointerMotionMask|ButtonPressMask|ExposureMask|KeyPressMask,
1560 &event);
1561 switch (event.type) {
1562 case KeyPress:
1563 if ((event.xkey.keycode == shiftl)
1564 || (event.xkey.keycode == shiftr)) {
1565 drawTransparentFrame(wwin,
1566 x - width/2, y - h/2, width, height);
1567 cyclePositionDisplay(wwin,
1568 x - width/2, y - h/2, width, height);
1569 drawTransparentFrame(wwin,
1570 x - width/2, y - h/2, width, height);
1572 break;
1574 case MotionNotify:
1575 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1577 x = event.xmotion.x_root;
1578 y = event.xmotion.y_root;
1580 if (wPreferences.move_display == WDIS_FRAME_CENTER)
1581 moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
1583 showPosition(wwin, x - width/2, y - h/2);
1585 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1587 break;
1589 case ButtonPress:
1590 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1591 XSync(dpy, 0);
1592 *x_ret = x - width/2;
1593 *y_ret = y - h/2;
1594 XUngrabPointer(dpy, CurrentTime);
1595 XUngrabKeyboard(dpy, CurrentTime);
1596 /* get rid of the geometry window */
1597 unmapPositionDisplay(wwin);
1598 return;
1600 default:
1601 WMHandleEvent(&event);
1602 break;