Update for 0.51.0
[wmaker-crm.git] / src / moveres.c
blob618e039022edf890f38c3fa0f350ed3f06b662ec
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 int kspeed = 1;
690 Time lastTime = 0;
691 KeySym keysym=NoSymbol;
692 KeyCode shiftl,shiftr,ctrll,ctrlmode;
695 int timer;
696 _looper looper;
697 looper.wwin=wwin;
698 scr->keymove_tick=1;
699 WMAddTimerHandler(1000,(WMCallback*)_keyloop, &looper);
702 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
703 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
704 ctrll = XKeysymToKeycode(dpy, XK_Control_L);
705 ctrlmode=done=off_x=off_y=0;
707 XSync(dpy, False);
708 wusleep(10000);
709 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
711 if (!wwin->flags.selected) {
712 wUnselectWindows(scr);
714 XGrabServer(dpy);
715 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
716 |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
717 GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime);
719 if (wwin->flags.shaded || scr->selected_windows) {
720 if(scr->selected_windows)
721 drawFrames(wwin,scr->selected_windows,off_x,off_y,0,0);
722 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
723 if(!scr->selected_windows)
724 mapPositionDisplay(wwin, src_x, src_y, w, h);
726 else {
727 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
729 ww=w;
730 wh=h;
731 while(1) {
733 looper.ox=off_x;
734 looper.oy=off_y;
736 WMMaskEvent(dpy, KeyPressMask | ButtonReleaseMask
737 | ButtonPressMask | ExposureMask, &event);
738 if (wwin->flags.shaded || scr->selected_windows) {
739 if(scr->selected_windows)
740 drawFrames(wwin,scr->selected_windows,off_x,off_y,0,0);
741 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
742 /*** I HATE EDGE RESISTANCE - ]d ***/
744 else {
745 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
748 if(ctrlmode)
749 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
751 XUngrabServer(dpy);
752 XSync(dpy, False);
754 switch (event.type) {
755 case KeyPress:
756 /* accelerate */
757 if (event.xkey.time - lastTime > 50) {
758 kspeed = 1;
759 } else {
760 if (kspeed < 20)
761 kspeed++;
763 lastTime = event.xkey.time;
765 if (event.xkey.state & ControlMask && !wwin->flags.shaded){
766 ctrlmode=1;
767 wUnselectWindows(scr);
769 else {
770 ctrlmode=0;
772 if (event.xkey.keycode == shiftl || event.xkey.keycode == shiftr){
773 if(ctrlmode)
774 cycleGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh, 0);
775 else
776 cyclePositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
778 else {
779 keysym = XLookupKeysym(&event.xkey, 0);
780 switch(keysym){
781 case XK_Return:
782 done=2;
783 break;
784 case XK_Escape:
785 done=1;
786 break;
787 case XK_Up:
788 case XK_KP_Up:
789 case XK_k:
790 if (ctrlmode){
791 h-=kspeed;
793 else off_y-=kspeed;
794 break;
795 case XK_Down:
796 case XK_KP_Down:
797 case XK_j:
798 if (ctrlmode){
799 h+=kspeed;
801 else off_y+=kspeed;
802 break;
803 case XK_Left:
804 case XK_KP_Left:
805 case XK_h:
806 if (ctrlmode){
807 w-=kspeed;
809 else off_x-=kspeed;
810 break;
811 case XK_Right:
812 case XK_KP_Right:
813 case XK_l:
814 if (ctrlmode){
815 w+=kspeed;
817 else off_x+=kspeed;
818 break;
820 ww=w;wh=h;
821 wh-=vert_border;
822 wWindowConstrainSize(wwin, &ww, &wh);
823 wh+=vert_border;
825 if (wPreferences.ws_cycle){
826 if (src_x + off_x + wwin->frame->core->width < 20){
827 if(!scr->current_workspace) {
828 wWorkspaceChange(scr, scr->workspace_count-1);
830 else wWorkspaceChange(scr, scr->current_workspace-1);
831 off_x += scr_width;
833 else if (src_x + off_x + 20 > scr_width){
834 if(scr->current_workspace == scr->workspace_count-1) {
835 wWorkspaceChange(scr, 0);
837 else wWorkspaceChange(scr, scr->current_workspace+1);
838 off_x -= scr_width;
841 else {
842 if (src_x + off_x + wwin->frame->core->width < 20)
843 off_x = 20 - wwin->frame->core->width - src_x;
844 else if (src_x + off_x + 20 > scr_width)
845 off_x = scr_width - 20 - src_x;
848 if (src_y + off_y + wwin->frame->core->height < 20)
849 off_y = 20 - wwin->frame->core->height - src_y;
850 else if (src_y + off_y + 20 > scr_height)
851 off_y = scr_height - 20 - src_y;
854 break;
855 case ButtonPress:
856 case ButtonRelease:
857 done=1;
858 break;
859 default:
860 WMHandleEvent(&event);
861 break;
864 XGrabServer(dpy);
865 /*xxx*/
867 if (wwin->flags.shaded && !scr->selected_windows){
868 moveGeometryDisplayCentered(scr, src_x+off_x + w/2, src_y+off_y + h/2);
870 else {
871 if(ctrlmode){
872 unmapPositionDisplay(wwin);
873 mapGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
875 else if(!scr->selected_windows){
876 unmapGeometryDisplay(wwin);
877 mapPositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
881 if (wwin->flags.shaded || scr->selected_windows) {
882 if(scr->selected_windows)
883 drawFrames(wwin,scr->selected_windows,off_x,off_y,0,0);
884 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
886 else {
887 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
891 if(ctrlmode){
892 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
894 else if(!scr->selected_windows)
895 showPosition(wwin, src_x+off_x, src_y+off_y);
896 /**/
898 if(done){
899 scr->keymove_tick=0;
901 WMDeleteTimerWithClientData(&looper);
903 if (wwin->flags.shaded || scr->selected_windows) {
904 if(scr->selected_windows)
905 drawFrames(wwin,scr->selected_windows,off_x,off_y,0,0);
906 else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
908 else {
909 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
912 if(ctrlmode){
913 showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
914 unmapGeometryDisplay(wwin);
916 else
917 unmapPositionDisplay(wwin);
918 XUngrabKeyboard(dpy, CurrentTime);
919 XUngrabPointer(dpy, CurrentTime);
920 XUngrabServer(dpy);
921 if(done==2){
922 if (wwin->flags.shaded || scr->selected_windows) {
923 LinkedList *list;
924 list=scr->selected_windows;
925 if(!scr->selected_windows){
926 wWindowMove(wwin, src_x+off_x, src_y+off_y);
927 wWindowSynthConfigureNotify(wwin);
929 else {
930 doWindowMove(wwin,0,0,scr->selected_windows,off_x,off_y,0,0);
931 while (list) {
932 wWindowSynthConfigureNotify(list->head);
933 list = list->tail;
937 else {
938 wWindowConfigure(wwin, src_x+off_x, src_y+off_y, ww, wh - vert_border);
939 wWindowSynthConfigureNotify(wwin);
941 wWindowChangeWorkspace(wwin, scr->current_workspace);
942 wSetFocusTo(scr, wwin);
944 return 1;
951 wMouseMoveWindow(WWindow *wwin, XEvent *ev)
953 WScreen *scr = wwin->screen_ptr;
954 XEvent event;
955 Window root = scr->root_win;
956 KeyCode shiftl, shiftr;
957 int w = wwin->frame->core->width;
958 int h = wwin->frame->core->height;
959 int x = wwin->frame_x;
960 int y = wwin->frame_y;
961 int ox, oy, orig_x, orig_y;
962 int off_x, off_y;
963 short count = 0; /* for automatic workspace creation */
964 int started = 0;
965 int warped = 0;
966 /* This needs not to change while moving, else bad things can happen */
967 int opaque_move = wPreferences.opaque_move;
968 int XOffset, YOffset, origDragX, origDragY;
970 origDragX = wwin->frame_x;
971 origDragY = wwin->frame_y;
972 XOffset = origDragX - ev->xbutton.x_root;
973 YOffset = origDragY - ev->xbutton.y_root;
975 if (!wwin->flags.selected) {
976 /* this window is not selected, unselect others and move only wwin */
977 wUnselectWindows(scr);
979 orig_x = ox = ev->xbutton.x_root;
980 orig_y = oy = ev->xbutton.y_root;
981 off_x = x; off_y = y;
982 checkEdgeResistance(wwin, &off_x, &off_y, 0, 0);
983 off_x = (off_x-x); off_y = (off_y-y);
984 #ifdef DEBUG
985 puts("Moving window");
986 #endif
987 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
988 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
989 while (1) {
990 if (warped) {
991 int junk;
992 Window junkw;
994 /* XWarpPointer() doesn't seem to generate Motion events, so
995 we've got to simulate them */
996 printf("warp\n");
997 XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
998 &event.xmotion.y_root, &junk, &junk,
999 (unsigned *) &junk);
1000 } else {
1001 Window win;
1003 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
1004 | ButtonReleaseMask | ButtonPressMask | ExposureMask, &event);
1006 if (event.type == MotionNotify) {
1007 /* compress MotionNotify events */
1008 win = event.xmotion.window;
1009 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
1012 switch (event.type) {
1013 case KeyPress:
1014 if (scr->selected_windows)
1015 break;
1016 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1017 && started) {
1018 if (!opaque_move)
1019 drawFrames(wwin, scr->selected_windows,
1020 ox - orig_x, oy - orig_y, off_x, off_y);
1022 cyclePositionDisplay(wwin, x, y, w, h);
1024 if (!opaque_move) {
1025 drawFrames(wwin, scr->selected_windows,
1026 ox - orig_x, oy - orig_y, off_x, off_y);
1028 showPosition(wwin, x, y);
1030 break;
1032 case MotionNotify:
1033 if (started) {
1034 showPosition(wwin, x, y);
1036 if (!opaque_move) {
1037 drawFrames(wwin, scr->selected_windows,
1038 ox-orig_x, oy-orig_y, off_x, off_y);
1039 } else {
1040 doWindowMove(wwin, event.xmotion.x_root + XOffset,
1041 event.xmotion.y_root + YOffset,
1042 scr->selected_windows,
1043 event.xmotion.x_root - ox,
1044 event.xmotion.y_root - oy,
1045 off_x, off_y);
1048 x = event.xmotion.x_root + XOffset;
1049 y = event.xmotion.y_root + YOffset;
1051 checkEdgeResistance(wwin, &x, &y, off_x, off_y);
1053 if (!scr->selected_windows) {
1054 if (wPreferences.move_display == WDIS_FRAME_CENTER)
1055 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
1057 if (!warped && !wPreferences.no_autowrap) {
1058 if (event.xmotion.x_root <= 1) {
1059 if (scr->current_workspace > 0) {
1060 crossWorkspace(scr, wwin, opaque_move,
1061 scr->current_workspace-1, True);
1062 warped = 1;
1063 count = 0;
1064 } else if (scr->current_workspace == 0
1065 && wPreferences.ws_cycle) {
1066 crossWorkspace(scr, wwin, opaque_move,
1067 scr->workspace_count-1, True);
1068 warped = 1;
1069 count = 0;
1071 } else if (event.xmotion.x_root >= scr->scr_width - 2) {
1073 if (scr->current_workspace == scr->workspace_count-1) {
1074 if ((!wPreferences.ws_advance && wPreferences.ws_cycle)
1075 || (scr->workspace_count == MAX_WORKSPACES)) {
1076 crossWorkspace(scr, wwin, opaque_move, 0, False);
1077 warped = 1;
1078 count = 0;
1080 /* if user insists on trying to go to next
1081 workspace even when it's already the last,
1082 create a new one */
1083 else if ((ox == event.xmotion.x_root)
1084 && wPreferences.ws_advance) {
1086 /* detect user "rubbing" the window
1087 against the edge */
1088 if (count > 0
1089 && oy - event.xmotion.y_root > MOVE_THRESHOLD)
1090 count = -(count + 1);
1091 else if (count <= 0
1092 && event.xmotion.y_root - oy > MOVE_THRESHOLD)
1093 count = -count + 1;
1095 /* create a new workspace */
1096 if (abs(count) > 2) {
1097 /* go to next workspace */
1098 wWorkspaceNew(scr);
1100 crossWorkspace(scr, wwin, opaque_move,
1101 scr->current_workspace+1, False);
1102 warped = 1;
1103 count = 0;
1105 } else if (scr->current_workspace < scr->workspace_count) {
1107 /* go to next workspace */
1108 crossWorkspace(scr, wwin, opaque_move,
1109 scr->current_workspace+1, False);
1110 warped = 1;
1111 count = 0;
1113 } else {
1114 count = 0;
1116 } else {
1117 warped = 0;
1119 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
1120 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1121 XChangeActivePointerGrab(dpy, ButtonMotionMask
1122 | ButtonReleaseMask | ButtonPressMask,
1123 wCursor[WCUR_MOVE], CurrentTime);
1124 started = 1;
1125 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
1126 CurrentTime);
1127 event.xmotion.x_root = orig_x;
1128 event.xmotion.y_root = orig_y;
1130 if (!scr->selected_windows)
1131 mapPositionDisplay(wwin, x, y, w, h);
1133 if (!opaque_move)
1134 XGrabServer(dpy);
1136 ox = event.xmotion.x_root;
1137 oy = event.xmotion.y_root;
1139 if (started && !opaque_move)
1140 drawFrames(wwin, scr->selected_windows, ox - orig_x, oy - orig_y, off_x, off_y);
1142 showPosition(wwin, x, y);
1143 break;
1145 case ButtonPress:
1146 break;
1148 case ButtonRelease:
1149 if (event.xbutton.button != ev->xbutton.button)
1150 break;
1152 if (started) {
1153 if (!opaque_move) {
1154 drawFrames(wwin, scr->selected_windows,
1155 ox - orig_x, oy - orig_y, off_x, off_y);
1156 XSync(dpy, 0);
1157 doWindowMove(wwin, event.xmotion.x_root + XOffset,
1158 event.xmotion.y_root + YOffset,
1159 scr->selected_windows,
1160 ox - orig_x, oy - orig_y,
1161 off_x, off_y);
1163 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
1164 wWindowSynthConfigureNotify(wwin);
1165 #endif
1167 XUngrabKeyboard(dpy, CurrentTime);
1168 XUngrabServer(dpy);
1169 if (!opaque_move) {
1170 wWindowChangeWorkspace(wwin, scr->current_workspace);
1171 wSetFocusTo(scr, wwin);
1173 showPosition(wwin, x, y);
1174 if (!scr->selected_windows) {
1175 /* get rid of the geometry window */
1176 unmapPositionDisplay(wwin);
1179 #ifdef DEBUG
1180 puts("End move window");
1181 #endif
1182 return started;
1184 default:
1185 if (started && !opaque_move) {
1186 drawFrames(wwin, scr->selected_windows, ox - orig_x, oy - orig_y, off_x, off_y);
1187 XUngrabServer(dpy);
1188 WMHandleEvent(&event);
1189 XSync(dpy, False);
1190 XGrabServer(dpy);
1191 drawFrames(wwin, scr->selected_windows, ox - orig_x, oy - orig_y, off_x, off_y);
1192 } else {
1193 WMHandleEvent(&event);
1195 break;
1198 return 0;
1202 #define RESIZEBAR 1
1203 #define HCONSTRAIN 2
1205 static int
1206 getResizeDirection(WWindow *wwin, int x, int y, int dx, int dy,
1207 int flags)
1209 int w = wwin->frame->core->width - 1;
1210 int cw = wwin->frame->resizebar_corner_width;
1211 int dir;
1213 /* if not resizing through the resizebar */
1214 if (!(flags & RESIZEBAR)) {
1215 int xdir = (abs(x) < (wwin->client.width/2)) ? LEFT : RIGHT;
1216 int ydir = (abs(y) < (wwin->client.height/2)) ? UP : DOWN;
1217 if (abs(dx) < 2 || abs(dy) < 2) {
1218 if (abs(dy) > abs(dx))
1219 xdir = 0;
1220 else
1221 ydir = 0;
1223 return (xdir | ydir);
1226 /* window is too narrow. allow diagonal resize */
1227 if (cw * 2 >= w) {
1228 int ydir;
1230 if (flags & HCONSTRAIN)
1231 ydir = 0;
1232 else
1233 ydir = DOWN;
1234 if (x < cw)
1235 return (LEFT | ydir);
1236 else
1237 return (RIGHT | ydir);
1239 /* vertical resize */
1240 if ((x > cw) && (x < w - cw))
1241 return DOWN;
1243 if (x < cw)
1244 dir = LEFT;
1245 else
1246 dir = RIGHT;
1248 if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
1249 dir |= DOWN;
1251 return dir;
1255 void
1256 wMouseResizeWindow(WWindow *wwin, XEvent *ev)
1258 XEvent event;
1259 WScreen *scr = wwin->screen_ptr;
1260 Window root = scr->root_win;
1261 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
1262 int fw = wwin->frame->core->width;
1263 int fh = wwin->frame->core->height;
1264 int fx = wwin->frame_x;
1265 int fy = wwin->frame_y;
1266 int is_resizebar = (wwin->frame->resizebar
1267 && ev->xany.window==wwin->frame->resizebar->window);
1268 int orig_x, orig_y;
1269 int started;
1270 int dw, dh;
1271 int rw = fw, rh = fh;
1272 int rx1, ry1, rx2, ry2;
1273 int res = 0;
1274 KeyCode shiftl, shiftr;
1275 int h = 0;
1276 int orig_fx = fx;
1277 int orig_fy = fy;
1278 int orig_fw = fw;
1279 int orig_fh = fh;
1281 if (wwin->flags.shaded) {
1282 wwarning("internal error: tryein");
1283 return;
1285 orig_x = ev->xbutton.x_root;
1286 orig_y = ev->xbutton.y_root;
1288 started = 0;
1289 #ifdef DEBUG
1290 puts("Resizing window");
1291 #endif
1293 wUnselectWindows(scr);
1294 rx1 = fx;
1295 rx2 = fx + fw - 1;
1296 ry1 = fy;
1297 ry2 = fy + fh - 1;
1298 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1299 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1300 if (!WFLAGP(wwin, no_titlebar))
1301 h = wwin->screen_ptr->title_font->height + TITLEBAR_EXTRA_HEIGHT;
1302 else
1303 h = 0;
1304 while (1) {
1305 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask | ButtonReleaseMask
1306 | ButtonPressMask | ExposureMask, &event);
1307 switch (event.type) {
1308 case KeyPress:
1309 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1310 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
1311 && started) {
1312 drawTransparentFrame(wwin, fx, fy, fw, fh);
1313 cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
1314 drawTransparentFrame(wwin, fx, fy, fw, fh);
1316 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1317 break;
1319 case MotionNotify:
1320 if (started) {
1321 dw = 0;
1322 dh = 0;
1324 orig_fx = fx;
1325 orig_fy = fy;
1326 orig_fw = fw;
1327 orig_fh = fh;
1329 if (res & LEFT)
1330 dw = orig_x - event.xmotion.x_root;
1331 else if (res & RIGHT)
1332 dw = event.xmotion.x_root - orig_x;
1333 if (res & UP)
1334 dh = orig_y - event.xmotion.y_root;
1335 else if (res & DOWN)
1336 dh = event.xmotion.y_root - orig_y;
1338 orig_x = event.xmotion.x_root;
1339 orig_y = event.xmotion.y_root;
1341 rw += dw;
1342 rh += dh;
1343 fw = rw;
1344 fh = rh - vert_border;
1345 wWindowConstrainSize(wwin, &fw, &fh);
1346 fh += vert_border;
1347 if (res & LEFT)
1348 fx = rx2 - fw + 1;
1349 else if (res & RIGHT)
1350 fx = rx1;
1351 if (res & UP)
1352 fy = ry2 - fh + 1;
1353 else if (res & DOWN)
1354 fy = ry1;
1355 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
1356 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1357 int tx, ty;
1358 Window junkw;
1359 int flags;
1361 XTranslateCoordinates(dpy, root, wwin->frame->core->window,
1362 orig_x, orig_y, &tx, &ty, &junkw);
1364 /* check if resizing through resizebar */
1365 if (is_resizebar)
1366 flags = RESIZEBAR;
1367 else
1368 flags = 0;
1370 if (is_resizebar && ((ev->xbutton.state & ShiftMask)
1371 || abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
1372 flags |= HCONSTRAIN;
1374 res = getResizeDirection(wwin, tx, ty,
1375 orig_x - event.xmotion.x_root,
1376 orig_y - event.xmotion.y_root, flags);
1378 XChangeActivePointerGrab(dpy, ButtonMotionMask
1379 | ButtonReleaseMask | ButtonPressMask,
1380 wCursor[WCUR_RESIZE], CurrentTime);
1381 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
1382 CurrentTime);
1384 XGrabServer(dpy);
1386 /* Draw the resize frame for the first time. */
1387 mapGeometryDisplay(wwin, fx, fy, fw, fh);
1389 drawTransparentFrame(wwin, fx, fy, fw, fh);
1391 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1393 started = 1;
1395 if (started) {
1396 if (wPreferences.size_display == WDIS_FRAME_CENTER) {
1397 drawTransparentFrame(wwin, orig_fx, orig_fy,
1398 orig_fw, orig_fh);
1399 moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
1400 drawTransparentFrame(wwin, fx, fy, fw, fh);
1401 } else {
1402 drawTransparentFrame(wwin, orig_fx, orig_fy,
1403 orig_fw, orig_fh);
1404 drawTransparentFrame(wwin, fx, fy, fw, fh);
1406 if (fh != orig_fh || fw != orig_fw) {
1407 if (wPreferences.size_display == WDIS_NEW) {
1408 showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw,
1409 orig_fy + orig_fh, res);
1411 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1414 break;
1416 case ButtonPress:
1417 break;
1419 case ButtonRelease:
1420 if (event.xbutton.button != ev->xbutton.button)
1421 break;
1423 if (started) {
1424 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1426 drawTransparentFrame(wwin, fx, fy, fw, fh);
1428 XUngrabKeyboard(dpy, CurrentTime);
1429 unmapGeometryDisplay(wwin);
1430 XUngrabServer(dpy);
1431 wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
1433 #ifdef DEBUG
1434 puts("End resize window");
1435 #endif
1436 return;
1438 default:
1439 WMHandleEvent(&event);
1444 #undef LEFT
1445 #undef RIGHT
1446 #undef HORIZONTAL
1447 #undef UP
1448 #undef DOWN
1449 #undef VERTICAL
1450 #undef HCONSTRAIN
1451 #undef RESIZEBAR
1453 void
1454 wUnselectWindows(WScreen *scr)
1456 WWindow *wwin;
1458 while (scr->selected_windows) {
1459 wwin = scr->selected_windows->head;
1460 if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
1461 wIconSelect(wwin->icon);
1463 wSelectWindow(wwin, False);
1467 #ifndef LITE
1468 static void
1469 selectWindowsInside(WScreen *scr, int x1, int y1, int x2, int y2)
1471 WWindow *tmpw;
1473 /* select the windows and put them in the selected window list */
1474 tmpw = scr->focused_window;
1475 while (tmpw != NULL) {
1476 if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
1477 if ((tmpw->frame->workspace == scr->current_workspace
1478 || IS_OMNIPRESENT(tmpw))
1479 && (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1)
1480 && (tmpw->frame->core->width + tmpw->frame_x <= x2)
1481 && (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
1482 wSelectWindow(tmpw, True);
1485 tmpw = tmpw->prev;
1490 void
1491 wSelectWindows(WScreen *scr, XEvent *ev)
1493 XEvent event;
1494 Window root = scr->root_win;
1495 GC gc = scr->frame_gc;
1496 int xp = ev->xbutton.x_root;
1497 int yp = ev->xbutton.y_root;
1498 int w = 0, h = 0;
1499 int x = xp, y = yp;
1501 #ifdef DEBUG
1502 puts("Selecting windows");
1503 #endif
1504 if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
1505 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
1506 GrabModeAsync, None, wCursor[WCUR_DEFAULT],
1507 CurrentTime) != Success) {
1508 return;
1510 XGrabServer(dpy);
1512 wUnselectWindows(scr);
1514 XDrawRectangle(dpy, root, gc, xp, yp, w, h);
1515 while (1) {
1516 WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask
1517 | ButtonPressMask, &event);
1519 switch (event.type) {
1520 case MotionNotify:
1521 XDrawRectangle(dpy, root, gc, x, y, w, h);
1522 x = event.xmotion.x_root;
1523 if (x < xp) {
1524 w = xp - x;
1525 } else {
1526 w = x - xp;
1527 x = xp;
1529 y = event.xmotion.y_root;
1530 if (y < yp) {
1531 h = yp - y;
1532 } else {
1533 h = y - yp;
1534 y = yp;
1536 XDrawRectangle(dpy, root, gc, x, y, w, h);
1537 break;
1539 case ButtonPress:
1540 break;
1542 case ButtonRelease:
1543 if (event.xbutton.button != ev->xbutton.button)
1544 break;
1546 XDrawRectangle(dpy, root, gc, x, y, w, h);
1547 XUngrabServer(dpy);
1548 XUngrabPointer(dpy, CurrentTime);
1549 selectWindowsInside(scr, x, y, x + w, y + h);
1550 #ifdef DEBUG
1551 puts("End window selection");
1552 #endif
1553 return;
1555 default:
1556 WMHandleEvent(&event);
1560 #endif /* !LITE */
1562 void
1563 InteractivePlaceWindow(WWindow *wwin, int *x_ret, int *y_ret,
1564 unsigned width, unsigned height)
1566 WScreen *scr = wwin->screen_ptr;
1567 Window root = scr->root_win;
1568 int x, y, h = 0;
1569 XEvent event;
1570 KeyCode shiftl, shiftr;
1571 Window junkw;
1572 int junk;
1574 if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
1575 GrabModeAsync, GrabModeAsync, None,
1576 wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
1577 *x_ret = 0;
1578 *y_ret = 0;
1579 return;
1581 if (!WFLAGP(wwin, no_titlebar)) {
1582 h = scr->title_font->height + TITLEBAR_EXTRA_HEIGHT;
1583 height += h;
1585 if (!WFLAGP(wwin, no_resizebar)) {
1586 height += RESIZEBAR_HEIGHT;
1588 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1589 XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk,
1590 (unsigned *) &junk);
1591 mapPositionDisplay(wwin, x - width/2, y - h/2, width, height);
1593 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1595 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1596 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1597 while (1) {
1598 WMMaskEvent(dpy, PointerMotionMask|ButtonPressMask|ExposureMask|KeyPressMask,
1599 &event);
1600 switch (event.type) {
1601 case KeyPress:
1602 if ((event.xkey.keycode == shiftl)
1603 || (event.xkey.keycode == shiftr)) {
1604 drawTransparentFrame(wwin,
1605 x - width/2, y - h/2, width, height);
1606 cyclePositionDisplay(wwin,
1607 x - width/2, y - h/2, width, height);
1608 drawTransparentFrame(wwin,
1609 x - width/2, y - h/2, width, height);
1611 break;
1613 case MotionNotify:
1614 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1616 x = event.xmotion.x_root;
1617 y = event.xmotion.y_root;
1619 if (wPreferences.move_display == WDIS_FRAME_CENTER)
1620 moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
1622 showPosition(wwin, x - width/2, y - h/2);
1624 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1626 break;
1628 case ButtonPress:
1629 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1630 XSync(dpy, 0);
1631 *x_ret = x - width/2;
1632 *y_ret = y - h/2;
1633 XUngrabPointer(dpy, CurrentTime);
1634 XUngrabKeyboard(dpy, CurrentTime);
1635 /* get rid of the geometry window */
1636 unmapPositionDisplay(wwin);
1637 return;
1639 default:
1640 WMHandleEvent(&event);
1641 break;