Updating to version 0.20.2
[wmaker-crm.git] / src / moveres.c
blobed055b5eecccd6c6ae2abbee2ff858f097d22da6
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 "funcs.h"
37 #include "actions.h"
38 #include "workspace.h"
40 #include "list.h"
42 /* How many different types of geometry/position
43 display thingies are there? */
44 #define NUM_DISPLAYS 4
46 #define LEFT 1
47 #define RIGHT 2
48 #define HORIZONTAL (LEFT|RIGHT)
49 #define UP 4
50 #define DOWN 8
51 #define VERTICAL (UP|DOWN)
53 /****** Global Variables ******/
54 extern Time LastTimestamp;
56 extern Cursor wCursor[WCUR_LAST];
58 extern WPreferences wPreferences;
60 extern Atom _XA_WM_PROTOCOLS;
62 /** Locals **/
63 static LinkedList *wSelectedWindows=NULL;
67 void
68 wGetGeometryWindowSize(WScreen *scr, unsigned int *width,
69 unsigned int *height)
71 #ifdef I18N_MB
72 *width = XmbTextEscapement(scr->info_text_font->font, "-8888 x -8888", 13);
73 *height = (7 * scr->info_text_font->height) / 4 - 1;
74 #else
75 *width = XTextWidth(scr->info_text_font->font, "-8888 x -8888", 13);
76 *height = (7 * scr->info_text_font->font->ascent) / 4 - 1;
77 #endif
82 *----------------------------------------------------------------------
83 * moveGeometryDisplayCentered
85 * routine that moves the geometry/position window on scr so it is
86 * centered over the given coordinates (x,y). Also the window position
87 * is clamped so it stays on the screen at all times.
88 *----------------------------------------------------------------------
90 static void
91 moveGeometryDisplayCentered(WScreen *scr, int x, int y)
93 x -= scr->geometry_display_width / 2;
94 y -= scr->geometry_display_height / 2;
96 if (x < 1)
97 x = 1;
98 else if (x > (scr->scr_width - scr->geometry_display_width - 3))
99 x = scr->scr_width - scr->geometry_display_width - 3;
101 if (y < 1)
102 y = 1;
103 else if (y > (scr->scr_height - scr->geometry_display_height - 3))
104 y = scr->scr_height - scr->geometry_display_height - 3;
106 XMoveWindow(dpy, scr->geometry_display, x, y);
110 static void
111 showPosition(WWindow *wwin, int x, int y)
113 WScreen *scr = wwin->screen_ptr;
114 GC gc = scr->info_text_gc;
115 char num[16];
116 int fw, fh;
118 if (wPreferences.move_display == WDIS_NEW) {
119 #if 0
120 int width = wwin->frame->core->width;
121 int height = wwin->frame->core->height;
123 GC lgc = scr->line_gc;
124 XSetForeground(dpy, lgc, scr->line_pixel);
125 sprintf(num, "%i", x);
127 XDrawLine(dpy, scr->root_win, lgc, 0, y-1, scr->scr_width, y-1);
128 XDrawLine(dpy, scr->root_win, lgc, 0, y+height+2, scr->scr_width,
129 y+height+2);
130 XDrawLine(dpy, scr->root_win, lgc, x-1, 0, x-1, scr->scr_height);
131 XDrawLine(dpy, scr->root_win, lgc, x+width+2, 0, x+width+2,
132 scr->scr_height);
133 #endif
134 } else {
135 XClearArea(dpy, scr->geometry_display, 1, 1,
136 scr->geometry_display_width-2, scr->geometry_display_height-2,
137 False);
138 sprintf(num, "%+i %-+i", x, y);
139 fw = wTextWidth(scr->info_text_font->font, num, strlen(num));
141 XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]);
143 fh = scr->info_text_font->height;
144 wDrawString(scr->geometry_display, scr->info_text_font, gc,
145 (scr->geometry_display_width - 2 - fw) / 2,
146 (scr->geometry_display_height-fh)/2 + scr->info_text_font->y,
147 num, strlen(num));
148 wDrawBevel(scr->geometry_display, scr->geometry_display_width+1,
149 scr->geometry_display_height+1, scr->resizebar_texture[0],
150 WREL_RAISED);
155 static void
156 cyclePositionDisplay(WWindow *wwin, int x, int y, int w, int h)
158 WScreen *scr = wwin->screen_ptr;
160 wPreferences.move_display++;
161 wPreferences.move_display %= NUM_DISPLAYS;
163 if (wPreferences.move_display == WDIS_NEW) {
164 XUnmapWindow(dpy, scr->geometry_display);
165 } else {
166 if (wPreferences.move_display == WDIS_CENTER) {
167 moveGeometryDisplayCentered(scr,
168 scr->scr_width/2, scr->scr_height/2);
169 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
170 moveGeometryDisplayCentered(scr, 1, 1);
171 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
172 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
174 XMapRaised(dpy, scr->geometry_display);
175 showPosition(wwin, x, y);
180 static void
181 mapPositionDisplay(WWindow *wwin, int x, int y, int w, int h)
183 WScreen *scr = wwin->screen_ptr;
185 if (wPreferences.move_display == WDIS_NEW) {
186 return;
187 } else if (wPreferences.move_display == WDIS_CENTER) {
188 moveGeometryDisplayCentered(scr, scr->scr_width / 2,
189 scr->scr_height / 2);
190 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
191 moveGeometryDisplayCentered(scr, 1, 1);
192 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
193 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
195 XMapRaised(dpy, scr->geometry_display);
196 showPosition(wwin, x, y);
199 #define unmapPositionDisplay(w) \
200 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
203 static void
204 showGeometry(WWindow *wwin, int x1, int y1, int x2, int y2, int direction)
206 WScreen *scr = wwin->screen_ptr;
207 Window root = scr->root_win;
208 GC gc = scr->line_gc;
209 int ty, by, my, x, y, mx, s;
210 char num[16];
211 XSegment segment[4];
212 int fw, fh;
214 ty = y1 + wwin->frame->top_width;
215 by = y2 - wwin->frame->bottom_width;
216 fw = wTextWidth(scr->info_text_font->font, "8888", 4);
217 fh = scr->info_text_font->height;
219 if (wPreferences.size_display == WDIS_NEW) {
220 XSetForeground(dpy, gc, scr->line_pixel);
222 /* vertical geometry */
223 if (((direction & LEFT) && (x2 < scr->scr_width - fw)) || (x1 < fw)) {
224 x = x2;
225 s = -15;
226 } else {
227 x = x1;
228 s = 15;
230 my = (ty + by) / 2;
232 /* top arrow */
233 /* end bar */
234 segment[0].x1 = x - (s + 6); segment[0].y1 = ty;
235 segment[0].x2 = x - (s - 10); segment[0].y2 = ty;
237 /* arrowhead */
238 segment[1].x1 = x - (s - 2); segment[1].y1 = ty + 1;
239 segment[1].x2 = x - (s - 5); segment[1].y2 = ty + 7;
241 segment[2].x1 = x - (s - 2); segment[2].y1 = ty + 1;
242 segment[2].x2 = x - (s + 1); segment[2].y2 = ty + 7;
244 /* line */
245 segment[3].x1 = x - (s - 2); segment[3].y1 = ty + 1;
246 segment[3].x2 = x - (s - 2); segment[3].y2 = my - fh/2 - 1;
248 XDrawSegments(dpy, root, gc, segment, 4);
250 /* bottom arrow */
251 /* end bar */
252 segment[0].y1 = by;
253 segment[0].y2 = by;
255 /* arrowhead */
256 segment[1].y1 = by - 1;
257 segment[1].y2 = by - 7;
259 segment[2].y1 = by - 1;
260 segment[2].y2 = by - 7;
262 /* line */
263 segment[3].y1 = my + fh/2 + 2;
264 segment[3].y2 = by - 1;
266 XDrawSegments(dpy, root, gc, segment, 4);
268 sprintf(num, "%i", (by - ty - wwin->normal_hints->base_height) /
269 wwin->normal_hints->height_inc);
270 fw = wTextWidth(scr->info_text_font->font, num, strlen(num));
272 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
274 /* Display the height. */
275 wDrawString(root, scr->info_text_font, gc,
276 x - s + 3 - fw/2, my - fh/2 + scr->info_text_font->y + 1,
277 num, strlen(num));
278 XSetForeground(dpy, gc, scr->line_pixel);
279 /* horizontal geometry */
280 if (y1 < 15) {
281 y = y2;
282 s = -15;
283 } else {
284 y = y1;
285 s = 15;
287 mx = x1 + (x2 - x1)/2;
288 sprintf(num, "%i", (x2 - x1 - wwin->normal_hints->base_width) /
289 wwin->normal_hints->width_inc);
290 fw = wTextWidth(scr->info_text_font->font, num, strlen(num));
292 /* left arrow */
293 /* end bar */
294 segment[0].x1 = x1; segment[0].y1 = y - (s + 6);
295 segment[0].x2 = x1; segment[0].y2 = y - (s - 10);
297 /* arrowhead */
298 segment[1].x1 = x1 + 7; segment[1].y1 = y - (s + 1);
299 segment[1].x2 = x1 + 1; segment[1].y2 = y - (s - 2);
301 segment[2].x1 = x1 + 1; segment[2].y1 = y - (s - 2);
302 segment[2].x2 = x1 + 7; segment[2].y2 = y - (s - 5);
304 /* line */
305 segment[3].x1 = x1 + 1; segment[3].y1 = y - (s - 2);
306 segment[3].x2 = mx - fw/2 - 2; segment[3].y2 = y - (s - 2);
308 XDrawSegments(dpy, root, gc, segment, 4);
310 /* right arrow */
311 /* end bar */
312 segment[0].x1 = x2 + 1;
313 segment[0].x2 = x2 + 1;
315 /* arrowhead */
316 segment[1].x1 = x2 - 6;
317 segment[1].x2 = x2;
319 segment[2].x1 = x2;
320 segment[2].x2 = x2 - 6;
322 /* line */
323 segment[3].x1 = mx + fw/2 + 2;
324 segment[3].x2 = x2;
326 XDrawSegments(dpy, root, gc, segment, 4);
328 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
330 /* Display the width. */
331 wDrawString(root, scr->info_text_font, gc,
332 mx - fw/2 + 1, y - s + fh/2 + 1, num, strlen(num));
333 } else {
334 XClearArea(dpy, scr->geometry_display, 1, 1,
335 scr->geometry_display_width-2, scr->geometry_display_height-2,
336 False);
337 sprintf(num, "%i x %-i", (x2 - x1 - wwin->normal_hints->base_width)
338 / wwin->normal_hints->width_inc,
339 (by - ty - wwin->normal_hints->base_height)
340 / wwin->normal_hints->height_inc);
341 fw = wTextWidth(scr->info_text_font->font, num, strlen(num));
343 XSetForeground(dpy, scr->info_text_gc,
344 scr->window_title_pixel[WS_UNFOCUSED]);
346 /* Display the height. */
347 wDrawString(scr->geometry_display, scr->info_text_font,
348 scr->info_text_gc,
349 (scr->geometry_display_width-fw)/2,
350 (scr->geometry_display_height-fh)/2 +scr->info_text_font->y,
351 num, strlen(num));
352 wDrawBevel(scr->geometry_display, scr->geometry_display_width+1,
353 scr->geometry_display_height+1, scr->resizebar_texture[0],
354 WREL_RAISED);
359 static void
360 cycleGeometryDisplay(WWindow *wwin, int x, int y, int w, int h, int dir)
362 WScreen *scr = wwin->screen_ptr;
364 wPreferences.size_display++;
365 wPreferences.size_display %= NUM_DISPLAYS;
367 if (wPreferences.size_display == WDIS_NEW) {
368 XUnmapWindow(dpy, scr->geometry_display);
369 } else {
370 if (wPreferences.size_display == WDIS_CENTER) {
371 moveGeometryDisplayCentered(scr,
372 scr->scr_width / 2, scr->scr_height / 2);
373 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
374 moveGeometryDisplayCentered(scr, 1, 1);
375 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
376 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
378 XMapRaised(dpy, scr->geometry_display);
379 showGeometry(wwin, x, y, x + w, y + h, dir);
384 static void
385 mapGeometryDisplay(WWindow *wwin, int x, int y, int w, int h)
387 WScreen *scr = wwin->screen_ptr;
389 if (wPreferences.size_display == WDIS_NEW)
390 return;
392 if (wPreferences.size_display == WDIS_CENTER) {
393 moveGeometryDisplayCentered(scr, scr->scr_width / 2,
394 scr->scr_height / 2);
395 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
396 moveGeometryDisplayCentered(scr, 1, 1);
397 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
398 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
400 XMapRaised(dpy, scr->geometry_display);
401 showGeometry(wwin, x, y, x + w, y + h, 0);
404 #define unmapGeometryDisplay(w) \
405 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
407 static void
408 checkEdgeResistance(WWindow *wwin, int *winx, int *winy, int off_x, int off_y)
410 int scr_width = wwin->screen_ptr->scr_width;
411 int scr_height = wwin->screen_ptr->scr_height;
412 int x = *winx;
413 int y = *winy;
414 int edge_resistance = wPreferences.edge_resistance;
416 x -= off_x;
417 y -= off_y;
419 if ((x + wwin->frame->core->width) >= (scr_width - 2)) {
420 if ((x + wwin->frame->core->width) < ((scr_width - 2)
421 + edge_resistance)) {
422 x = scr_width - wwin->frame->core->width - 2;
423 } else {
424 x -= edge_resistance;
428 if (x <= 0) {
429 if (x > -edge_resistance) {
430 x = 0;
431 } else {
432 x += edge_resistance;
436 if ((y + wwin->frame->core->height) >= (scr_height - 1)) {
437 if ((y + wwin->frame->core->height) < ((scr_height - 1)
438 + edge_resistance)) {
439 y = scr_height - wwin->frame->core->height - 1;
440 } else {
441 y -= edge_resistance;
445 if (y <=0) {
446 if (y > -edge_resistance) {
447 y = 0;
448 } else {
449 y += edge_resistance;
454 *winx = x;
455 *winy = y;
458 static void
459 doWindowMove(WWindow *wwin, int single_win_x, int single_win_y,
460 LinkedList *list, int dx, int dy, int off_x, int off_y)
462 WWindow *tmpw;
463 int x, y;
464 int scr_width = wwin->screen_ptr->scr_width;
465 int scr_height = wwin->screen_ptr->scr_height;
467 if (!list) {
468 checkEdgeResistance(wwin, &single_win_x, &single_win_y, off_x, off_y);
469 wWindowMove(wwin, single_win_x, single_win_y);
470 } else {
471 while (list) {
472 tmpw = list->head;
473 x = tmpw->frame_x + dx;
474 y = tmpw->frame_y + dy;
476 /* don't let windows become unreachable */
478 if (x + (int)tmpw->frame->core->width < 20)
479 x = 20 - (int)tmpw->frame->core->width;
480 else if (x + 20 > scr_width)
481 x = scr_width - 20;
483 if (y + (int)tmpw->frame->core->height < 20)
484 y = 20 - (int)tmpw->frame->core->height;
485 else if (y + 20 > scr_height)
486 y = scr_height - 20;
488 wWindowMove(tmpw, x, y);
489 list = list->tail;
495 static void
496 drawTransparentFrame(WWindow *wwin, int x, int y, int width, int height)
498 Window root = wwin->screen_ptr->root_win;
499 GC gc = wwin->screen_ptr->frame_gc;
500 int h = 0;
501 int bottom = 0;
503 if (!wwin->window_flags.no_titlebar && !wwin->flags.shaded) {
504 h = wwin->screen_ptr->title_font->height + TITLEBAR_EXTRA_HEIGHT;
506 if (!wwin->window_flags.no_resizebar && !wwin->flags.shaded) {
507 /* Can't use wwin-frame->bottom_width because, in some cases
508 (e.g. interactive placement), frame does not point to anything. */
509 bottom = RESIZEBAR_HEIGHT - 1;
511 XDrawRectangle(dpy, root, gc, x, y, width + 1, height + 1);
513 if (h > 0) {
514 XDrawLine(dpy, root, gc, x + 1, y + h, x + width + 1, y + h);
516 if (bottom > 0) {
517 XDrawLine(dpy, root, gc, x + 1,
518 y + height - bottom,
519 x + width + 1,
520 y + height - bottom);
525 static void
526 drawFrames(WWindow *wwin, LinkedList *list, int dx, int dy, int off_x, int off_y)
528 WWindow *tmpw;
529 int scr_width = wwin->screen_ptr->scr_width;
530 int scr_height = wwin->screen_ptr->scr_height;
531 int x, y;
533 if (!list) {
535 x = wwin->frame_x + dx;
536 y = wwin->frame_y + dy;
538 checkEdgeResistance(wwin, &x, &y, off_x, off_y);
539 drawTransparentFrame(wwin, x, y,
540 wwin->frame->core->width,
541 wwin->frame->core->height);
543 } else {
544 while (list) {
545 tmpw = list->head;
546 x = tmpw->frame_x + dx;
547 y = tmpw->frame_y + dy;
549 /* don't let windows become unreachable */
551 if (x + (int)tmpw->frame->core->width < 20)
552 x = 20 - (int)tmpw->frame->core->width;
553 else if (x + 20 > scr_width)
554 x = scr_width - 20;
556 if (y + (int)tmpw->frame->core->height < 20)
557 y = 20 - (int)tmpw->frame->core->height;
558 else if (y + 20 > scr_height)
559 y = scr_height - 20;
561 drawTransparentFrame(tmpw, x, y, tmpw->frame->core->width,
562 tmpw->frame->core->height);
564 list = list->tail;
571 static void
572 flushMotion()
574 XEvent ev;
576 XSync(dpy, 0);
577 while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
581 static void
582 crossWorkspace(WScreen *scr, WWindow *wwin, int opaque_move,
583 int new_workspace, int rewind)
585 /* do not let window be unmapped */
586 if (opaque_move) {
587 wwin->flags.changing_workspace = 1;
588 wWindowChangeWorkspace(wwin, new_workspace);
590 /* go to new workspace */
591 wWorkspaceChange(scr, new_workspace);
593 wwin->flags.changing_workspace = 0;
595 if (rewind)
596 XWarpPointer(dpy, None, None, 0, 0, 0, 0, scr->scr_width - 20, 0);
597 else
598 XWarpPointer(dpy, None, None, 0, 0, 0, 0, -(scr->scr_width - 20), 0);
600 flushMotion();
602 if (!opaque_move) {
603 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
604 |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
605 GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
611 *----------------------------------------------------------------------
612 * wMouseMoveWindow--
613 * Move the named window and the other selected ones (if any),
614 * interactively. Also shows the position of the window, if only one
615 * window is being moved.
616 * If the window is not on the selected window list, the selected
617 * windows are deselected.
618 * If shift is pressed during the operation, the position display
619 * is changed to another type.
621 * Returns:
622 * True if the window was moved, False otherwise.
624 * Side effects:
625 * The window(s) position is changed, and the client(s) are
626 * notified about that.
627 * The position display configuration may be changed.
628 *----------------------------------------------------------------------
631 wMouseMoveWindow(WWindow *wwin, XEvent *ev)
633 WScreen *scr = wwin->screen_ptr;
634 XEvent event;
635 Window root = scr->root_win;
636 KeyCode shiftl, shiftr;
637 int w = wwin->frame->core->width;
638 int h = wwin->frame->core->height;
639 int x = wwin->frame_x;
640 int y = wwin->frame_y;
641 int ox, oy, orig_x, orig_y;
642 int off_x, off_y;
643 short count = 0; /* for automatic workspace creation */
644 int started = 0;
645 int warped = 0;
646 /* This needs not to change while moving, else bad things can happen */
647 int opaque_move = wPreferences.opaque_move;
648 int XOffset, YOffset, origDragX, origDragY;
650 origDragX = wwin->frame_x;
651 origDragY = wwin->frame_y;
652 XOffset = origDragX - ev->xbutton.x_root;
653 YOffset = origDragY - ev->xbutton.y_root;
655 if (!wwin->flags.selected) {
656 /* this window is not selected, unselect others and move only wwin */
657 wUnselectWindows();
659 orig_x = ox = ev->xbutton.x_root;
660 orig_y = oy = ev->xbutton.y_root;
661 off_x = x; off_y = y;
662 checkEdgeResistance(wwin, &off_x, &off_y, 0, 0);
663 off_x = (off_x-x); off_y = (off_y-y);
664 #ifdef DEBUG
665 puts("Moving window");
666 #endif
667 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
668 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
669 while (1) {
670 if (warped) {
671 int junk;
672 Window junkw;
674 /* XWarpPointer() doesn't seem to generate Motion events, so
675 we've got to simulate them */
676 XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
677 &event.xmotion.y_root, &junk, &junk,
678 (unsigned *) &junk);
679 } else {
680 Window win;
682 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
683 | ButtonReleaseMask | ButtonPressMask | ExposureMask, &event);
685 if (event.type == MotionNotify) {
686 /* compress MotionNotify events */
687 win = event.xmotion.window;
688 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
691 switch (event.type) {
692 case KeyPress:
693 if (wSelectedWindows)
694 break;
695 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
696 && started) {
697 if (!opaque_move)
698 drawFrames(wwin, wSelectedWindows,
699 ox - orig_x, oy - orig_y, off_x, off_y);
701 cyclePositionDisplay(wwin, x, y, w, h);
703 if (!opaque_move) {
704 drawFrames(wwin, wSelectedWindows,
705 ox - orig_x, oy - orig_y, off_x, off_y);
707 showPosition(wwin, x, y);
709 break;
711 case MotionNotify:
712 if (started) {
713 showPosition(wwin, x, y);
715 if (!opaque_move) {
716 drawFrames(wwin, wSelectedWindows,
717 ox-orig_x, oy-orig_y, off_x, off_y);
718 } else {
719 doWindowMove(wwin, event.xmotion.x_root + XOffset,
720 event.xmotion.y_root + YOffset,
721 wSelectedWindows,
722 event.xmotion.x_root - ox,
723 event.xmotion.y_root - oy,
724 off_x, off_y);
727 x = event.xmotion.x_root + XOffset;
728 y = event.xmotion.y_root + YOffset;
730 checkEdgeResistance(wwin, &x, &y, off_x, off_y);
732 if (!wSelectedWindows) {
733 if (wPreferences.move_display == WDIS_FRAME_CENTER)
734 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
736 if (!warped && !wPreferences.no_autowrap) {
737 if (event.xmotion.x_root <= 1) {
738 if (scr->current_workspace > 0) {
739 crossWorkspace(scr, wwin, opaque_move,
740 scr->current_workspace-1, True);
741 warped = 1;
742 count = 0;
743 } else if (scr->current_workspace == 0
744 && wPreferences.ws_cycle) {
745 crossWorkspace(scr, wwin, opaque_move,
746 scr->workspace_count-1, True);
747 warped = 1;
748 count = 0;
750 } else if (event.xmotion.x_root >= scr->scr_width - 2) {
752 if (scr->current_workspace == scr->workspace_count-1) {
753 if ((!wPreferences.ws_advance && wPreferences.ws_cycle)
754 || (scr->workspace_count == MAX_WORKSPACES)) {
755 crossWorkspace(scr, wwin, opaque_move, 0, False);
756 warped = 1;
757 count = 0;
759 /* if user insists on trying to go to next
760 workspace even when it's already the last,
761 create a new one */
762 else if ((ox == event.xmotion.x_root)
763 && wPreferences.ws_advance) {
765 /* detect user "rubbing" the window
766 against the edge */
767 if (count > 0
768 && oy - event.xmotion.y_root > MOVE_THRESHOLD)
769 count = -(count + 1);
770 else if (count <= 0
771 && event.xmotion.y_root - oy > MOVE_THRESHOLD)
772 count = -count + 1;
774 /* create a new workspace */
775 if (abs(count) > 2) {
776 /* go to next workspace */
777 wWorkspaceNew(scr);
779 crossWorkspace(scr, wwin, opaque_move,
780 scr->current_workspace+1, False);
781 warped = 1;
782 count = 0;
784 } else if (scr->current_workspace < scr->workspace_count) {
786 /* go to next workspace */
787 crossWorkspace(scr, wwin, opaque_move,
788 scr->current_workspace+1, False);
789 warped = 1;
790 count = 0;
792 } else {
793 count = 0;
795 } else {
796 warped = 0;
798 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
799 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
800 XChangeActivePointerGrab(dpy, ButtonMotionMask
801 | ButtonReleaseMask | ButtonPressMask,
802 wCursor[WCUR_MOVE], CurrentTime);
803 started = 1;
804 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
805 CurrentTime);
806 event.xmotion.x_root = orig_x;
807 event.xmotion.y_root = orig_y;
809 if (!wSelectedWindows)
810 mapPositionDisplay(wwin, x, y, w, h);
812 if (!opaque_move)
813 XGrabServer(dpy);
815 ox = event.xmotion.x_root;
816 oy = event.xmotion.y_root;
818 if (started && !opaque_move)
819 drawFrames(wwin, wSelectedWindows, ox - orig_x, oy - orig_y, off_x, off_y);
821 showPosition(wwin, x, y);
822 break;
824 case ButtonPress:
825 break;
827 case ButtonRelease:
828 if (event.xbutton.button != ev->xbutton.button)
829 break;
831 if (started) {
832 if (!opaque_move) {
833 drawFrames(wwin, wSelectedWindows,
834 ox - orig_x, oy - orig_y, off_x, off_y);
835 XSync(dpy, 0);
836 doWindowMove(wwin, event.xmotion.x_root + XOffset,
837 event.xmotion.y_root + YOffset,
838 wSelectedWindows,
839 ox - orig_x, oy - orig_y,
840 off_x, off_y);
842 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
843 wWindowSynthConfigureNotify(wwin);
844 #endif
846 XUngrabKeyboard(dpy, CurrentTime);
847 XUngrabServer(dpy);
848 if (!opaque_move) {
849 wWindowChangeWorkspace(wwin, scr->current_workspace);
850 wSetFocusTo(scr, wwin);
852 showPosition(wwin, x, y);
853 if (!wSelectedWindows) {
854 /* get rid of the geometry window */
855 unmapPositionDisplay(wwin);
858 #ifdef DEBUG
859 puts("End move window");
860 #endif
861 return started;
863 default:
864 if (started && !opaque_move) {
865 drawFrames(wwin, wSelectedWindows, ox - orig_x, oy - orig_y, off_x, off_y);
866 XUngrabServer(dpy);
867 WMHandleEvent(&event);
868 XSync(dpy, False);
869 XGrabServer(dpy);
870 drawFrames(wwin, wSelectedWindows, ox - orig_x, oy - orig_y, off_x, off_y);
871 } else {
872 WMHandleEvent(&event);
874 break;
877 return 0;
881 #define RESIZEBAR 1
882 #define HCONSTRAIN 2
884 static int
885 getResizeDirection(WWindow *wwin, int x, int y, int dx, int dy,
886 int flags)
888 int w = wwin->frame->core->width - 1;
889 int cw = wwin->frame->resizebar_corner_width;
890 int dir;
892 /* if not resizing through the resizebar */
893 if (!(flags & RESIZEBAR)) {
894 int xdir = (abs(x) < (wwin->client.width/2)) ? LEFT : RIGHT;
895 int ydir = (abs(y) < (wwin->client.height/2)) ? UP : DOWN;
896 if (abs(dx) < 2 || abs(dy) < 2) {
897 if (abs(dy) > abs(dx))
898 xdir = 0;
899 else
900 ydir = 0;
902 return (xdir | ydir);
905 /* window is too narrow. allow diagonal resize */
906 if (cw * 2 >= w) {
907 int ydir;
909 if (flags & HCONSTRAIN)
910 ydir = 0;
911 else
912 ydir = DOWN;
913 if (x < cw)
914 return (LEFT | ydir);
915 else
916 return (RIGHT | ydir);
918 /* vertical resize */
919 if ((x > cw) && (x < w - cw))
920 return DOWN;
922 if (x < cw)
923 dir = LEFT;
924 else
925 dir = RIGHT;
927 if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
928 dir |= DOWN;
930 return dir;
934 void
935 wMouseResizeWindow(WWindow *wwin, XEvent *ev)
937 XEvent event;
938 WScreen *scr = wwin->screen_ptr;
939 Window root = scr->root_win;
940 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
941 int fw = wwin->frame->core->width;
942 int fh = wwin->frame->core->height;
943 int fx = wwin->frame_x;
944 int fy = wwin->frame_y;
945 int is_resizebar = (wwin->frame->resizebar
946 && ev->xany.window==wwin->frame->resizebar->window);
947 int orig_x, orig_y;
948 int started;
949 int dw, dh;
950 int rw = fw, rh = fh;
951 int rx1, ry1, rx2, ry2;
952 int res = 0;
953 KeyCode shiftl, shiftr;
954 int h = 0;
955 int orig_fx = fx;
956 int orig_fy = fy;
957 int orig_fw = fw;
958 int orig_fh = fh;
960 if (wwin->flags.shaded) {
961 wwarning("internal error: tryein");
962 return;
964 orig_x = ev->xbutton.x_root;
965 orig_y = ev->xbutton.y_root;
967 started = 0;
968 #ifdef DEBUG
969 puts("Resizing window");
970 #endif
972 wUnselectWindows();
973 rx1 = fx;
974 rx2 = fx + fw - 1;
975 ry1 = fy;
976 ry2 = fy + fh - 1;
977 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
978 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
979 if (!wwin->window_flags.no_titlebar)
980 h = wwin->screen_ptr->title_font->height + TITLEBAR_EXTRA_HEIGHT;
981 else
982 h = 0;
983 while (1) {
984 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask | ButtonReleaseMask
985 | ButtonPressMask | ExposureMask, &event);
986 switch (event.type) {
987 case KeyPress:
988 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
989 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
990 && started) {
991 drawTransparentFrame(wwin, fx, fy, fw, fh);
992 cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
993 drawTransparentFrame(wwin, fx, fy, fw, fh);
995 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
996 break;
998 case MotionNotify:
999 if (started) {
1000 dw = 0;
1001 dh = 0;
1003 orig_fx = fx;
1004 orig_fy = fy;
1005 orig_fw = fw;
1006 orig_fh = fh;
1008 if (res & LEFT)
1009 dw = orig_x - event.xmotion.x_root;
1010 else if (res & RIGHT)
1011 dw = event.xmotion.x_root - orig_x;
1012 if (res & UP)
1013 dh = orig_y - event.xmotion.y_root;
1014 else if (res & DOWN)
1015 dh = event.xmotion.y_root - orig_y;
1017 orig_x = event.xmotion.x_root;
1018 orig_y = event.xmotion.y_root;
1020 rw += dw;
1021 rh += dh;
1022 fw = rw;
1023 fh = rh - vert_border;
1024 wWindowConstrainSize(wwin, &fw, &fh);
1025 fh += vert_border;
1026 if (res & LEFT)
1027 fx = rx2 - fw + 1;
1028 else if (res & RIGHT)
1029 fx = rx1;
1030 if (res & UP)
1031 fy = ry2 - fh + 1;
1032 else if (res & DOWN)
1033 fy = ry1;
1034 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
1035 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1036 int tx, ty;
1037 Window junkw;
1038 int flags;
1040 XTranslateCoordinates(dpy, root, wwin->frame->core->window,
1041 orig_x, orig_y, &tx, &ty, &junkw);
1043 /* check if resizing through resizebar */
1044 if (is_resizebar)
1045 flags = RESIZEBAR;
1046 else
1047 flags = 0;
1049 if (is_resizebar && ((ev->xbutton.state & ShiftMask)
1050 || abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
1051 flags |= HCONSTRAIN;
1053 res = getResizeDirection(wwin, tx, ty,
1054 orig_x - event.xmotion.x_root,
1055 orig_y - event.xmotion.y_root, flags);
1057 XChangeActivePointerGrab(dpy, ButtonMotionMask
1058 | ButtonReleaseMask | ButtonPressMask,
1059 wCursor[WCUR_RESIZE], CurrentTime);
1060 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
1061 CurrentTime);
1063 XGrabServer(dpy);
1065 /* Draw the resize frame for the first time. */
1066 mapGeometryDisplay(wwin, fx, fy, fw, fh);
1068 drawTransparentFrame(wwin, fx, fy, fw, fh);
1070 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1072 started = 1;
1074 if (started) {
1075 if (wPreferences.size_display == WDIS_FRAME_CENTER) {
1076 drawTransparentFrame(wwin, orig_fx, orig_fy,
1077 orig_fw, orig_fh);
1078 moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
1079 drawTransparentFrame(wwin, fx, fy, fw, fh);
1080 } else {
1081 drawTransparentFrame(wwin, orig_fx, orig_fy,
1082 orig_fw, orig_fh);
1083 drawTransparentFrame(wwin, fx, fy, fw, fh);
1085 if (fh != orig_fh || fw != orig_fw) {
1086 if (wPreferences.size_display == WDIS_NEW) {
1087 showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw,
1088 orig_fy + orig_fh, res);
1090 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1093 break;
1095 case ButtonPress:
1096 break;
1098 case ButtonRelease:
1099 if (event.xbutton.button != ev->xbutton.button)
1100 break;
1102 if (started) {
1103 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1105 drawTransparentFrame(wwin, fx, fy, fw, fh);
1107 XUngrabKeyboard(dpy, CurrentTime);
1108 unmapGeometryDisplay(wwin);
1109 XUngrabServer(dpy);
1110 wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
1112 #ifdef DEBUG
1113 puts("End resize window");
1114 #endif
1115 return;
1117 default:
1118 WMHandleEvent(&event);
1123 #undef LEFT
1124 #undef RIGHT
1125 #undef HORIZONTAL
1126 #undef UP
1127 #undef DOWN
1128 #undef VERTICAL
1129 #undef HCONSTRAIN
1130 #undef RESIZEBAR
1132 void
1133 wUnselectWindows()
1135 WWindow *wwin;
1137 while (wSelectedWindows) {
1138 wwin = wSelectedWindows->head;
1139 if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
1140 wIconSelect(wwin->icon);
1142 XSetWindowBorder(dpy, wwin->frame->core->window,
1143 wwin->screen_ptr->frame_border_pixel);
1144 wwin->flags.selected = 0;
1145 list_remove_head(&wSelectedWindows);
1150 void
1151 wSelectWindow(WWindow *wwin)
1153 if (!wwin->flags.selected) {
1154 wwin->flags.selected = 1;
1155 XSetWindowBorder(dpy, wwin->frame->core->window,
1156 wwin->screen_ptr->white_pixel);
1157 wSelectedWindows = list_cons(wwin, wSelectedWindows);
1158 } else {
1159 wwin->flags.selected = 0;
1160 XSetWindowBorder(dpy, wwin->frame->core->window,
1161 wwin->screen_ptr->frame_border_pixel);
1162 wSelectedWindows = list_remove_elem(wSelectedWindows, wwin);
1167 static void
1168 selectWindowsInside(WScreen *scr, int x1, int y1, int x2, int y2)
1170 WWindow *tmpw;
1172 /* select the windows and put them in the selected window list */
1173 tmpw = scr->focused_window;
1174 while (tmpw != NULL) {
1175 if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
1176 if ((tmpw->frame->workspace == scr->current_workspace
1177 || tmpw->window_flags.omnipresent)
1178 && (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1)
1179 && (tmpw->frame->core->width + tmpw->frame_x <= x2)
1180 && (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
1181 XSetWindowBorder(dpy, tmpw->frame->core->window,
1182 tmpw->screen_ptr->white_pixel);
1183 tmpw->flags.selected = 1;
1184 wSelectedWindows = list_cons(tmpw, wSelectedWindows);
1187 tmpw = tmpw->prev;
1192 void
1193 wSelectWindows(WScreen *scr, XEvent *ev)
1195 XEvent event;
1196 Window root = scr->root_win;
1197 GC gc = scr->frame_gc;
1198 int xp = ev->xbutton.x_root;
1199 int yp = ev->xbutton.y_root;
1200 int w = 0, h = 0;
1201 int x = xp, y = yp;
1203 #ifdef DEBUG
1204 puts("Selecting windows");
1205 #endif
1206 if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
1207 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
1208 GrabModeAsync, None, wCursor[WCUR_DEFAULT],
1209 CurrentTime) != Success) {
1210 return;
1212 XGrabServer(dpy);
1214 wUnselectWindows();
1216 XDrawRectangle(dpy, root, gc, xp, yp, w, h);
1217 while (1) {
1218 WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask
1219 | ButtonPressMask, &event);
1221 switch (event.type) {
1222 case MotionNotify:
1223 XDrawRectangle(dpy, root, gc, x, y, w, h);
1224 x = event.xmotion.x_root;
1225 if (x < xp) {
1226 w = xp - x;
1227 } else {
1228 w = x - xp;
1229 x = xp;
1231 y = event.xmotion.y_root;
1232 if (y < yp) {
1233 h = yp - y;
1234 } else {
1235 h = y - yp;
1236 y = yp;
1238 XDrawRectangle(dpy, root, gc, x, y, w, h);
1239 break;
1241 case ButtonPress:
1242 break;
1244 case ButtonRelease:
1245 if (event.xbutton.button != ev->xbutton.button)
1246 break;
1248 XDrawRectangle(dpy, root, gc, x, y, w, h);
1249 XUngrabServer(dpy);
1250 XUngrabPointer(dpy, CurrentTime);
1251 selectWindowsInside(scr, x, y, x + w, y + h);
1252 #ifdef DEBUG
1253 puts("End window selection");
1254 #endif
1255 return;
1257 default:
1258 WMHandleEvent(&event);
1264 void
1265 InteractivePlaceWindow(WWindow *wwin, int *x_ret, int *y_ret)
1267 WScreen *scr = wwin->screen_ptr;
1268 Window root = scr->root_win;
1269 int x, y, h = 0;
1270 int width = wwin->client.width;
1271 int height = wwin->client.height;
1272 XEvent event;
1273 KeyCode shiftl, shiftr;
1274 Window junkw;
1275 int junk;
1277 if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
1278 GrabModeAsync, GrabModeAsync, None,
1279 wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
1280 *x_ret = 0;
1281 *y_ret = 0;
1282 return;
1284 if (!wwin->window_flags.no_titlebar) {
1285 h = scr->title_font->height + TITLEBAR_EXTRA_HEIGHT;
1286 height += h;
1288 if (!wwin->window_flags.no_resizebar) {
1289 height += RESIZEBAR_HEIGHT;
1291 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1292 XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk,
1293 (unsigned *) &junk);
1294 mapPositionDisplay(wwin, x - width/2, y - h/2, width, height);
1296 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1298 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1299 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1300 while (1) {
1301 WMMaskEvent(dpy, PointerMotionMask|ButtonPressMask|ExposureMask|KeyPressMask,
1302 &event);
1303 switch (event.type) {
1304 case KeyPress:
1305 if ((event.xkey.keycode == shiftl)
1306 || (event.xkey.keycode == shiftr)) {
1307 drawTransparentFrame(wwin,
1308 x - width/2, y - h/2, width, height);
1309 cyclePositionDisplay(wwin,
1310 x - width/2, y - h/2, width, height);
1311 drawTransparentFrame(wwin,
1312 x - width/2, y - h/2, width, height);
1314 break;
1316 case MotionNotify:
1317 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1319 x = event.xmotion.x_root;
1320 y = event.xmotion.y_root;
1322 if (wPreferences.move_display == WDIS_FRAME_CENTER)
1323 moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
1325 showPosition(wwin, x - width/2, y - h/2);
1327 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1329 break;
1331 case ButtonPress:
1332 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1333 XSync(dpy, 0);
1334 *x_ret = x - width/2;
1335 *y_ret = y - h/2;
1336 XUngrabPointer(dpy, CurrentTime);
1337 XUngrabKeyboard(dpy, CurrentTime);
1338 /* get rid of the geometry window */
1339 unmapPositionDisplay(wwin);
1340 return;
1342 default:
1343 WMHandleEvent(&event);
1344 break;