Window Maker 0.20.3
[wmaker-crm.git] / src / moveres.c
blobc11e94575c191fe37d8a9ceeb5ec51b4b098e8cc
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;
64 void
65 wGetGeometryWindowSize(WScreen *scr, unsigned int *width,
66 unsigned int *height)
68 #ifdef I18N_MB
69 *width = XmbTextEscapement(scr->info_text_font->font, "-8888 x -8888", 13);
70 *height = (7 * scr->info_text_font->height) / 4 - 1;
71 #else
72 *width = XTextWidth(scr->info_text_font->font, "-8888 x -8888", 13);
73 *height = (7 * scr->info_text_font->font->ascent) / 4 - 1;
74 #endif
79 *----------------------------------------------------------------------
80 * moveGeometryDisplayCentered
82 * routine that moves the geometry/position window on scr so it is
83 * centered over the given coordinates (x,y). Also the window position
84 * is clamped so it stays on the screen at all times.
85 *----------------------------------------------------------------------
87 static void
88 moveGeometryDisplayCentered(WScreen *scr, int x, int y)
90 x -= scr->geometry_display_width / 2;
91 y -= scr->geometry_display_height / 2;
93 if (x < 1)
94 x = 1;
95 else if (x > (scr->scr_width - scr->geometry_display_width - 3))
96 x = scr->scr_width - scr->geometry_display_width - 3;
98 if (y < 1)
99 y = 1;
100 else if (y > (scr->scr_height - scr->geometry_display_height - 3))
101 y = scr->scr_height - scr->geometry_display_height - 3;
103 XMoveWindow(dpy, scr->geometry_display, x, y);
107 static void
108 showPosition(WWindow *wwin, int x, int y)
110 WScreen *scr = wwin->screen_ptr;
111 GC gc = scr->info_text_gc;
112 char num[16];
113 int fw, fh;
115 if (wPreferences.move_display == WDIS_NEW) {
116 #if 0
117 int width = wwin->frame->core->width;
118 int height = wwin->frame->core->height;
120 GC lgc = scr->line_gc;
121 XSetForeground(dpy, lgc, scr->line_pixel);
122 sprintf(num, "%i", x);
124 XDrawLine(dpy, scr->root_win, lgc, 0, y-1, scr->scr_width, y-1);
125 XDrawLine(dpy, scr->root_win, lgc, 0, y+height+2, scr->scr_width,
126 y+height+2);
127 XDrawLine(dpy, scr->root_win, lgc, x-1, 0, x-1, scr->scr_height);
128 XDrawLine(dpy, scr->root_win, lgc, x+width+2, 0, x+width+2,
129 scr->scr_height);
130 #endif
131 } else {
132 XClearArea(dpy, scr->geometry_display, 1, 1,
133 scr->geometry_display_width-2, scr->geometry_display_height-2,
134 False);
135 sprintf(num, "%+i %-+i", x, y);
136 fw = wTextWidth(scr->info_text_font->font, num, strlen(num));
138 XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]);
140 fh = scr->info_text_font->height;
141 wDrawString(scr->geometry_display, scr->info_text_font, gc,
142 (scr->geometry_display_width - 2 - fw) / 2,
143 (scr->geometry_display_height-fh)/2 + scr->info_text_font->y,
144 num, strlen(num));
145 wDrawBevel(scr->geometry_display, scr->geometry_display_width+1,
146 scr->geometry_display_height+1, scr->resizebar_texture[0],
147 WREL_RAISED);
152 static void
153 cyclePositionDisplay(WWindow *wwin, int x, int y, int w, int h)
155 WScreen *scr = wwin->screen_ptr;
157 wPreferences.move_display++;
158 wPreferences.move_display %= NUM_DISPLAYS;
160 if (wPreferences.move_display == WDIS_NEW) {
161 XUnmapWindow(dpy, scr->geometry_display);
162 } else {
163 if (wPreferences.move_display == WDIS_CENTER) {
164 moveGeometryDisplayCentered(scr,
165 scr->scr_width/2, scr->scr_height/2);
166 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
167 moveGeometryDisplayCentered(scr, 1, 1);
168 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
169 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
171 XMapRaised(dpy, scr->geometry_display);
172 showPosition(wwin, x, y);
177 static void
178 mapPositionDisplay(WWindow *wwin, int x, int y, int w, int h)
180 WScreen *scr = wwin->screen_ptr;
182 if (wPreferences.move_display == WDIS_NEW) {
183 return;
184 } else if (wPreferences.move_display == WDIS_CENTER) {
185 moveGeometryDisplayCentered(scr, scr->scr_width / 2,
186 scr->scr_height / 2);
187 } else if (wPreferences.move_display == WDIS_TOPLEFT) {
188 moveGeometryDisplayCentered(scr, 1, 1);
189 } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
190 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
192 XMapRaised(dpy, scr->geometry_display);
193 showPosition(wwin, x, y);
196 #define unmapPositionDisplay(w) \
197 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
200 static void
201 showGeometry(WWindow *wwin, int x1, int y1, int x2, int y2, int direction)
203 WScreen *scr = wwin->screen_ptr;
204 Window root = scr->root_win;
205 GC gc = scr->line_gc;
206 int ty, by, my, x, y, mx, s;
207 char num[16];
208 XSegment segment[4];
209 int fw, fh;
211 ty = y1 + wwin->frame->top_width;
212 by = y2 - wwin->frame->bottom_width;
213 fw = wTextWidth(scr->info_text_font->font, "8888", 4);
214 fh = scr->info_text_font->height;
216 if (wPreferences.size_display == WDIS_NEW) {
217 XSetForeground(dpy, gc, scr->line_pixel);
219 /* vertical geometry */
220 if (((direction & LEFT) && (x2 < scr->scr_width - fw)) || (x1 < fw)) {
221 x = x2;
222 s = -15;
223 } else {
224 x = x1;
225 s = 15;
227 my = (ty + by) / 2;
229 /* top arrow */
230 /* end bar */
231 segment[0].x1 = x - (s + 6); segment[0].y1 = ty;
232 segment[0].x2 = x - (s - 10); segment[0].y2 = ty;
234 /* arrowhead */
235 segment[1].x1 = x - (s - 2); segment[1].y1 = ty + 1;
236 segment[1].x2 = x - (s - 5); segment[1].y2 = ty + 7;
238 segment[2].x1 = x - (s - 2); segment[2].y1 = ty + 1;
239 segment[2].x2 = x - (s + 1); segment[2].y2 = ty + 7;
241 /* line */
242 segment[3].x1 = x - (s - 2); segment[3].y1 = ty + 1;
243 segment[3].x2 = x - (s - 2); segment[3].y2 = my - fh/2 - 1;
245 XDrawSegments(dpy, root, gc, segment, 4);
247 /* bottom arrow */
248 /* end bar */
249 segment[0].y1 = by;
250 segment[0].y2 = by;
252 /* arrowhead */
253 segment[1].y1 = by - 1;
254 segment[1].y2 = by - 7;
256 segment[2].y1 = by - 1;
257 segment[2].y2 = by - 7;
259 /* line */
260 segment[3].y1 = my + fh/2 + 2;
261 segment[3].y2 = by - 1;
263 XDrawSegments(dpy, root, gc, segment, 4);
265 sprintf(num, "%i", (by - ty - wwin->normal_hints->base_height) /
266 wwin->normal_hints->height_inc);
267 fw = wTextWidth(scr->info_text_font->font, num, strlen(num));
269 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
271 /* Display the height. */
272 wDrawString(root, scr->info_text_font, gc,
273 x - s + 3 - fw/2, my - fh/2 + scr->info_text_font->y + 1,
274 num, strlen(num));
275 XSetForeground(dpy, gc, scr->line_pixel);
276 /* horizontal geometry */
277 if (y1 < 15) {
278 y = y2;
279 s = -15;
280 } else {
281 y = y1;
282 s = 15;
284 mx = x1 + (x2 - x1)/2;
285 sprintf(num, "%i", (x2 - x1 - wwin->normal_hints->base_width) /
286 wwin->normal_hints->width_inc);
287 fw = wTextWidth(scr->info_text_font->font, num, strlen(num));
289 /* left arrow */
290 /* end bar */
291 segment[0].x1 = x1; segment[0].y1 = y - (s + 6);
292 segment[0].x2 = x1; segment[0].y2 = y - (s - 10);
294 /* arrowhead */
295 segment[1].x1 = x1 + 7; segment[1].y1 = y - (s + 1);
296 segment[1].x2 = x1 + 1; segment[1].y2 = y - (s - 2);
298 segment[2].x1 = x1 + 1; segment[2].y1 = y - (s - 2);
299 segment[2].x2 = x1 + 7; segment[2].y2 = y - (s - 5);
301 /* line */
302 segment[3].x1 = x1 + 1; segment[3].y1 = y - (s - 2);
303 segment[3].x2 = mx - fw/2 - 2; segment[3].y2 = y - (s - 2);
305 XDrawSegments(dpy, root, gc, segment, 4);
307 /* right arrow */
308 /* end bar */
309 segment[0].x1 = x2 + 1;
310 segment[0].x2 = x2 + 1;
312 /* arrowhead */
313 segment[1].x1 = x2 - 6;
314 segment[1].x2 = x2;
316 segment[2].x1 = x2;
317 segment[2].x2 = x2 - 6;
319 /* line */
320 segment[3].x1 = mx + fw/2 + 2;
321 segment[3].x2 = x2;
323 XDrawSegments(dpy, root, gc, segment, 4);
325 /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
327 /* Display the width. */
328 wDrawString(root, scr->info_text_font, gc,
329 mx - fw/2 + 1, y - s + fh/2 + 1, num, strlen(num));
330 } else {
331 XClearArea(dpy, scr->geometry_display, 1, 1,
332 scr->geometry_display_width-2, scr->geometry_display_height-2,
333 False);
334 sprintf(num, "%i x %-i", (x2 - x1 - wwin->normal_hints->base_width)
335 / wwin->normal_hints->width_inc,
336 (by - ty - wwin->normal_hints->base_height)
337 / wwin->normal_hints->height_inc);
338 fw = wTextWidth(scr->info_text_font->font, num, strlen(num));
340 XSetForeground(dpy, scr->info_text_gc,
341 scr->window_title_pixel[WS_UNFOCUSED]);
343 /* Display the height. */
344 wDrawString(scr->geometry_display, scr->info_text_font,
345 scr->info_text_gc,
346 (scr->geometry_display_width-fw)/2,
347 (scr->geometry_display_height-fh)/2 +scr->info_text_font->y,
348 num, strlen(num));
349 wDrawBevel(scr->geometry_display, scr->geometry_display_width+1,
350 scr->geometry_display_height+1, scr->resizebar_texture[0],
351 WREL_RAISED);
356 static void
357 cycleGeometryDisplay(WWindow *wwin, int x, int y, int w, int h, int dir)
359 WScreen *scr = wwin->screen_ptr;
361 wPreferences.size_display++;
362 wPreferences.size_display %= NUM_DISPLAYS;
364 if (wPreferences.size_display == WDIS_NEW) {
365 XUnmapWindow(dpy, scr->geometry_display);
366 } else {
367 if (wPreferences.size_display == WDIS_CENTER) {
368 moveGeometryDisplayCentered(scr,
369 scr->scr_width / 2, scr->scr_height / 2);
370 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
371 moveGeometryDisplayCentered(scr, 1, 1);
372 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
373 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
375 XMapRaised(dpy, scr->geometry_display);
376 showGeometry(wwin, x, y, x + w, y + h, dir);
381 static void
382 mapGeometryDisplay(WWindow *wwin, int x, int y, int w, int h)
384 WScreen *scr = wwin->screen_ptr;
386 if (wPreferences.size_display == WDIS_NEW)
387 return;
389 if (wPreferences.size_display == WDIS_CENTER) {
390 moveGeometryDisplayCentered(scr, scr->scr_width / 2,
391 scr->scr_height / 2);
392 } else if (wPreferences.size_display == WDIS_TOPLEFT) {
393 moveGeometryDisplayCentered(scr, 1, 1);
394 } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
395 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
397 XMapRaised(dpy, scr->geometry_display);
398 showGeometry(wwin, x, y, x + w, y + h, 0);
401 #define unmapGeometryDisplay(w) \
402 XUnmapWindow(dpy, (w)->screen_ptr->geometry_display);
404 static void
405 checkEdgeResistance(WWindow *wwin, int *winx, int *winy, int off_x, int off_y)
407 int scr_width = wwin->screen_ptr->scr_width;
408 int scr_height = wwin->screen_ptr->scr_height;
409 int x = *winx;
410 int y = *winy;
411 int edge_resistance = wPreferences.edge_resistance;
413 x -= off_x;
414 y -= off_y;
416 if ((x + wwin->frame->core->width) >= (scr_width - 2)) {
417 if ((x + wwin->frame->core->width) < ((scr_width - 2)
418 + edge_resistance)) {
419 x = scr_width - wwin->frame->core->width - 2;
420 } else {
421 x -= edge_resistance;
425 if (x <= 0) {
426 if (x > -edge_resistance) {
427 x = 0;
428 } else {
429 x += edge_resistance;
433 if ((y + wwin->frame->core->height) >= (scr_height - 1)) {
434 if ((y + wwin->frame->core->height) < ((scr_height - 1)
435 + edge_resistance)) {
436 y = scr_height - wwin->frame->core->height - 1;
437 } else {
438 y -= edge_resistance;
442 if (y <=0) {
443 if (y > -edge_resistance) {
444 y = 0;
445 } else {
446 y += edge_resistance;
451 *winx = x;
452 *winy = y;
455 static void
456 doWindowMove(WWindow *wwin, int single_win_x, int single_win_y,
457 LinkedList *list, int dx, int dy, int off_x, int off_y)
459 WWindow *tmpw;
460 int x, y;
461 int scr_width = wwin->screen_ptr->scr_width;
462 int scr_height = wwin->screen_ptr->scr_height;
464 if (!list) {
465 checkEdgeResistance(wwin, &single_win_x, &single_win_y, off_x, off_y);
466 wWindowMove(wwin, single_win_x, single_win_y);
467 } else {
468 while (list) {
469 tmpw = list->head;
470 x = tmpw->frame_x + dx;
471 y = tmpw->frame_y + dy;
473 /* don't let windows become unreachable */
475 if (x + (int)tmpw->frame->core->width < 20)
476 x = 20 - (int)tmpw->frame->core->width;
477 else if (x + 20 > scr_width)
478 x = scr_width - 20;
480 if (y + (int)tmpw->frame->core->height < 20)
481 y = 20 - (int)tmpw->frame->core->height;
482 else if (y + 20 > scr_height)
483 y = scr_height - 20;
485 wWindowMove(tmpw, x, y);
486 list = list->tail;
492 static void
493 drawTransparentFrame(WWindow *wwin, int x, int y, int width, int height)
495 Window root = wwin->screen_ptr->root_win;
496 GC gc = wwin->screen_ptr->frame_gc;
497 int h = 0;
498 int bottom = 0;
500 if (!wwin->window_flags.no_titlebar && !wwin->flags.shaded) {
501 h = wwin->screen_ptr->title_font->height + TITLEBAR_EXTRA_HEIGHT;
503 if (!wwin->window_flags.no_resizebar && !wwin->flags.shaded) {
504 /* Can't use wwin-frame->bottom_width because, in some cases
505 (e.g. interactive placement), frame does not point to anything. */
506 bottom = RESIZEBAR_HEIGHT - 1;
508 XDrawRectangle(dpy, root, gc, x, y, width + 1, height + 1);
510 if (h > 0) {
511 XDrawLine(dpy, root, gc, x + 1, y + h, x + width + 1, y + h);
513 if (bottom > 0) {
514 XDrawLine(dpy, root, gc, x + 1,
515 y + height - bottom,
516 x + width + 1,
517 y + height - bottom);
522 static void
523 drawFrames(WWindow *wwin, LinkedList *list, int dx, int dy, int off_x, int off_y)
525 WWindow *tmpw;
526 int scr_width = wwin->screen_ptr->scr_width;
527 int scr_height = wwin->screen_ptr->scr_height;
528 int x, y;
530 if (!list) {
532 x = wwin->frame_x + dx;
533 y = wwin->frame_y + dy;
535 checkEdgeResistance(wwin, &x, &y, off_x, off_y);
536 drawTransparentFrame(wwin, x, y,
537 wwin->frame->core->width,
538 wwin->frame->core->height);
540 } else {
541 while (list) {
542 tmpw = list->head;
543 x = tmpw->frame_x + dx;
544 y = tmpw->frame_y + dy;
546 /* don't let windows become unreachable */
548 if (x + (int)tmpw->frame->core->width < 20)
549 x = 20 - (int)tmpw->frame->core->width;
550 else if (x + 20 > scr_width)
551 x = scr_width - 20;
553 if (y + (int)tmpw->frame->core->height < 20)
554 y = 20 - (int)tmpw->frame->core->height;
555 else if (y + 20 > scr_height)
556 y = scr_height - 20;
558 drawTransparentFrame(tmpw, x, y, tmpw->frame->core->width,
559 tmpw->frame->core->height);
561 list = list->tail;
568 static void
569 flushMotion()
571 XEvent ev;
573 while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
577 static void
578 crossWorkspace(WScreen *scr, WWindow *wwin, int opaque_move,
579 int new_workspace, int rewind)
581 /* do not let window be unmapped */
582 if (opaque_move) {
583 wwin->flags.changing_workspace = 1;
584 wWindowChangeWorkspace(wwin, new_workspace);
586 /* go to new workspace */
587 wWorkspaceChange(scr, new_workspace);
589 wwin->flags.changing_workspace = 0;
591 if (rewind)
592 XWarpPointer(dpy, None, None, 0, 0, 0, 0, scr->scr_width - 20, 0);
593 else
594 XWarpPointer(dpy, None, None, 0, 0, 0, 0, -(scr->scr_width - 20), 0);
596 flushMotion();
598 if (!opaque_move) {
599 XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
600 |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
601 GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
607 *----------------------------------------------------------------------
608 * wMouseMoveWindow--
609 * Move the named window and the other selected ones (if any),
610 * interactively. Also shows the position of the window, if only one
611 * window is being moved.
612 * If the window is not on the selected window list, the selected
613 * windows are deselected.
614 * If shift is pressed during the operation, the position display
615 * is changed to another type.
617 * Returns:
618 * True if the window was moved, False otherwise.
620 * Side effects:
621 * The window(s) position is changed, and the client(s) are
622 * notified about that.
623 * The position display configuration may be changed.
624 *----------------------------------------------------------------------
627 wMouseMoveWindow(WWindow *wwin, XEvent *ev)
629 WScreen *scr = wwin->screen_ptr;
630 XEvent event;
631 Window root = scr->root_win;
632 KeyCode shiftl, shiftr;
633 int w = wwin->frame->core->width;
634 int h = wwin->frame->core->height;
635 int x = wwin->frame_x;
636 int y = wwin->frame_y;
637 int ox, oy, orig_x, orig_y;
638 int off_x, off_y;
639 short count = 0; /* for automatic workspace creation */
640 int started = 0;
641 int warped = 0;
642 /* This needs not to change while moving, else bad things can happen */
643 int opaque_move = wPreferences.opaque_move;
644 int XOffset, YOffset, origDragX, origDragY;
646 origDragX = wwin->frame_x;
647 origDragY = wwin->frame_y;
648 XOffset = origDragX - ev->xbutton.x_root;
649 YOffset = origDragY - ev->xbutton.y_root;
651 if (!wwin->flags.selected) {
652 /* this window is not selected, unselect others and move only wwin */
653 wUnselectWindows(scr);
655 orig_x = ox = ev->xbutton.x_root;
656 orig_y = oy = ev->xbutton.y_root;
657 off_x = x; off_y = y;
658 checkEdgeResistance(wwin, &off_x, &off_y, 0, 0);
659 off_x = (off_x-x); off_y = (off_y-y);
660 #ifdef DEBUG
661 puts("Moving window");
662 #endif
663 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
664 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
665 while (1) {
666 if (warped) {
667 int junk;
668 Window junkw;
670 /* XWarpPointer() doesn't seem to generate Motion events, so
671 we've got to simulate them */
672 XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
673 &event.xmotion.y_root, &junk, &junk,
674 (unsigned *) &junk);
675 } else {
676 Window win;
678 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
679 | ButtonReleaseMask | ButtonPressMask | ExposureMask, &event);
681 if (event.type == MotionNotify) {
682 /* compress MotionNotify events */
683 win = event.xmotion.window;
684 while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
687 switch (event.type) {
688 case KeyPress:
689 if (scr->selected_windows)
690 break;
691 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
692 && started) {
693 if (!opaque_move)
694 drawFrames(wwin, scr->selected_windows,
695 ox - orig_x, oy - orig_y, off_x, off_y);
697 cyclePositionDisplay(wwin, x, y, w, h);
699 if (!opaque_move) {
700 drawFrames(wwin, scr->selected_windows,
701 ox - orig_x, oy - orig_y, off_x, off_y);
703 showPosition(wwin, x, y);
705 break;
707 case MotionNotify:
708 if (started) {
709 showPosition(wwin, x, y);
711 if (!opaque_move) {
712 drawFrames(wwin, scr->selected_windows,
713 ox-orig_x, oy-orig_y, off_x, off_y);
714 } else {
715 doWindowMove(wwin, event.xmotion.x_root + XOffset,
716 event.xmotion.y_root + YOffset,
717 scr->selected_windows,
718 event.xmotion.x_root - ox,
719 event.xmotion.y_root - oy,
720 off_x, off_y);
723 x = event.xmotion.x_root + XOffset;
724 y = event.xmotion.y_root + YOffset;
726 checkEdgeResistance(wwin, &x, &y, off_x, off_y);
728 if (!scr->selected_windows) {
729 if (wPreferences.move_display == WDIS_FRAME_CENTER)
730 moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
732 if (!warped && !wPreferences.no_autowrap) {
733 if (event.xmotion.x_root <= 1) {
734 if (scr->current_workspace > 0) {
735 crossWorkspace(scr, wwin, opaque_move,
736 scr->current_workspace-1, True);
737 warped = 1;
738 count = 0;
739 } else if (scr->current_workspace == 0
740 && wPreferences.ws_cycle) {
741 crossWorkspace(scr, wwin, opaque_move,
742 scr->workspace_count-1, True);
743 warped = 1;
744 count = 0;
746 } else if (event.xmotion.x_root >= scr->scr_width - 2) {
748 if (scr->current_workspace == scr->workspace_count-1) {
749 if ((!wPreferences.ws_advance && wPreferences.ws_cycle)
750 || (scr->workspace_count == MAX_WORKSPACES)) {
751 crossWorkspace(scr, wwin, opaque_move, 0, False);
752 warped = 1;
753 count = 0;
755 /* if user insists on trying to go to next
756 workspace even when it's already the last,
757 create a new one */
758 else if ((ox == event.xmotion.x_root)
759 && wPreferences.ws_advance) {
761 /* detect user "rubbing" the window
762 against the edge */
763 if (count > 0
764 && oy - event.xmotion.y_root > MOVE_THRESHOLD)
765 count = -(count + 1);
766 else if (count <= 0
767 && event.xmotion.y_root - oy > MOVE_THRESHOLD)
768 count = -count + 1;
770 /* create a new workspace */
771 if (abs(count) > 2) {
772 /* go to next workspace */
773 wWorkspaceNew(scr);
775 crossWorkspace(scr, wwin, opaque_move,
776 scr->current_workspace+1, False);
777 warped = 1;
778 count = 0;
780 } else if (scr->current_workspace < scr->workspace_count) {
782 /* go to next workspace */
783 crossWorkspace(scr, wwin, opaque_move,
784 scr->current_workspace+1, False);
785 warped = 1;
786 count = 0;
788 } else {
789 count = 0;
791 } else {
792 warped = 0;
794 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
795 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
796 XChangeActivePointerGrab(dpy, ButtonMotionMask
797 | ButtonReleaseMask | ButtonPressMask,
798 wCursor[WCUR_MOVE], CurrentTime);
799 started = 1;
800 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
801 CurrentTime);
802 event.xmotion.x_root = orig_x;
803 event.xmotion.y_root = orig_y;
805 if (!scr->selected_windows)
806 mapPositionDisplay(wwin, x, y, w, h);
808 if (!opaque_move)
809 XGrabServer(dpy);
811 ox = event.xmotion.x_root;
812 oy = event.xmotion.y_root;
814 if (started && !opaque_move)
815 drawFrames(wwin, scr->selected_windows, ox - orig_x, oy - orig_y, off_x, off_y);
817 showPosition(wwin, x, y);
818 break;
820 case ButtonPress:
821 break;
823 case ButtonRelease:
824 if (event.xbutton.button != ev->xbutton.button)
825 break;
827 if (started) {
828 if (!opaque_move) {
829 drawFrames(wwin, scr->selected_windows,
830 ox - orig_x, oy - orig_y, off_x, off_y);
831 XSync(dpy, 0);
832 doWindowMove(wwin, event.xmotion.x_root + XOffset,
833 event.xmotion.y_root + YOffset,
834 scr->selected_windows,
835 ox - orig_x, oy - orig_y,
836 off_x, off_y);
838 #ifndef CONFIGURE_WINDOW_WHILE_MOVING
839 wWindowSynthConfigureNotify(wwin);
840 #endif
842 XUngrabKeyboard(dpy, CurrentTime);
843 XUngrabServer(dpy);
844 if (!opaque_move) {
845 wWindowChangeWorkspace(wwin, scr->current_workspace);
846 wSetFocusTo(scr, wwin);
848 showPosition(wwin, x, y);
849 if (!scr->selected_windows) {
850 /* get rid of the geometry window */
851 unmapPositionDisplay(wwin);
854 #ifdef DEBUG
855 puts("End move window");
856 #endif
857 return started;
859 default:
860 if (started && !opaque_move) {
861 drawFrames(wwin, scr->selected_windows, ox - orig_x, oy - orig_y, off_x, off_y);
862 XUngrabServer(dpy);
863 WMHandleEvent(&event);
864 XSync(dpy, False);
865 XGrabServer(dpy);
866 drawFrames(wwin, scr->selected_windows, ox - orig_x, oy - orig_y, off_x, off_y);
867 } else {
868 WMHandleEvent(&event);
870 break;
873 return 0;
877 #define RESIZEBAR 1
878 #define HCONSTRAIN 2
880 static int
881 getResizeDirection(WWindow *wwin, int x, int y, int dx, int dy,
882 int flags)
884 int w = wwin->frame->core->width - 1;
885 int cw = wwin->frame->resizebar_corner_width;
886 int dir;
888 /* if not resizing through the resizebar */
889 if (!(flags & RESIZEBAR)) {
890 int xdir = (abs(x) < (wwin->client.width/2)) ? LEFT : RIGHT;
891 int ydir = (abs(y) < (wwin->client.height/2)) ? UP : DOWN;
892 if (abs(dx) < 2 || abs(dy) < 2) {
893 if (abs(dy) > abs(dx))
894 xdir = 0;
895 else
896 ydir = 0;
898 return (xdir | ydir);
901 /* window is too narrow. allow diagonal resize */
902 if (cw * 2 >= w) {
903 int ydir;
905 if (flags & HCONSTRAIN)
906 ydir = 0;
907 else
908 ydir = DOWN;
909 if (x < cw)
910 return (LEFT | ydir);
911 else
912 return (RIGHT | ydir);
914 /* vertical resize */
915 if ((x > cw) && (x < w - cw))
916 return DOWN;
918 if (x < cw)
919 dir = LEFT;
920 else
921 dir = RIGHT;
923 if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
924 dir |= DOWN;
926 return dir;
930 void
931 wMouseResizeWindow(WWindow *wwin, XEvent *ev)
933 XEvent event;
934 WScreen *scr = wwin->screen_ptr;
935 Window root = scr->root_win;
936 int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
937 int fw = wwin->frame->core->width;
938 int fh = wwin->frame->core->height;
939 int fx = wwin->frame_x;
940 int fy = wwin->frame_y;
941 int is_resizebar = (wwin->frame->resizebar
942 && ev->xany.window==wwin->frame->resizebar->window);
943 int orig_x, orig_y;
944 int started;
945 int dw, dh;
946 int rw = fw, rh = fh;
947 int rx1, ry1, rx2, ry2;
948 int res = 0;
949 KeyCode shiftl, shiftr;
950 int h = 0;
951 int orig_fx = fx;
952 int orig_fy = fy;
953 int orig_fw = fw;
954 int orig_fh = fh;
956 if (wwin->flags.shaded) {
957 wwarning("internal error: tryein");
958 return;
960 orig_x = ev->xbutton.x_root;
961 orig_y = ev->xbutton.y_root;
963 started = 0;
964 #ifdef DEBUG
965 puts("Resizing window");
966 #endif
968 wUnselectWindows(scr);
969 rx1 = fx;
970 rx2 = fx + fw - 1;
971 ry1 = fy;
972 ry2 = fy + fh - 1;
973 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
974 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
975 if (!wwin->window_flags.no_titlebar)
976 h = wwin->screen_ptr->title_font->height + TITLEBAR_EXTRA_HEIGHT;
977 else
978 h = 0;
979 while (1) {
980 WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask | ButtonReleaseMask
981 | ButtonPressMask | ExposureMask, &event);
982 switch (event.type) {
983 case KeyPress:
984 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
985 if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
986 && started) {
987 drawTransparentFrame(wwin, fx, fy, fw, fh);
988 cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
989 drawTransparentFrame(wwin, fx, fy, fw, fh);
991 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
992 break;
994 case MotionNotify:
995 if (started) {
996 dw = 0;
997 dh = 0;
999 orig_fx = fx;
1000 orig_fy = fy;
1001 orig_fw = fw;
1002 orig_fh = fh;
1004 if (res & LEFT)
1005 dw = orig_x - event.xmotion.x_root;
1006 else if (res & RIGHT)
1007 dw = event.xmotion.x_root - orig_x;
1008 if (res & UP)
1009 dh = orig_y - event.xmotion.y_root;
1010 else if (res & DOWN)
1011 dh = event.xmotion.y_root - orig_y;
1013 orig_x = event.xmotion.x_root;
1014 orig_y = event.xmotion.y_root;
1016 rw += dw;
1017 rh += dh;
1018 fw = rw;
1019 fh = rh - vert_border;
1020 wWindowConstrainSize(wwin, &fw, &fh);
1021 fh += vert_border;
1022 if (res & LEFT)
1023 fx = rx2 - fw + 1;
1024 else if (res & RIGHT)
1025 fx = rx1;
1026 if (res & UP)
1027 fy = ry2 - fh + 1;
1028 else if (res & DOWN)
1029 fy = ry1;
1030 } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
1031 || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
1032 int tx, ty;
1033 Window junkw;
1034 int flags;
1036 XTranslateCoordinates(dpy, root, wwin->frame->core->window,
1037 orig_x, orig_y, &tx, &ty, &junkw);
1039 /* check if resizing through resizebar */
1040 if (is_resizebar)
1041 flags = RESIZEBAR;
1042 else
1043 flags = 0;
1045 if (is_resizebar && ((ev->xbutton.state & ShiftMask)
1046 || abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
1047 flags |= HCONSTRAIN;
1049 res = getResizeDirection(wwin, tx, ty,
1050 orig_x - event.xmotion.x_root,
1051 orig_y - event.xmotion.y_root, flags);
1053 XChangeActivePointerGrab(dpy, ButtonMotionMask
1054 | ButtonReleaseMask | ButtonPressMask,
1055 wCursor[WCUR_RESIZE], CurrentTime);
1056 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
1057 CurrentTime);
1059 XGrabServer(dpy);
1061 /* Draw the resize frame for the first time. */
1062 mapGeometryDisplay(wwin, fx, fy, fw, fh);
1064 drawTransparentFrame(wwin, fx, fy, fw, fh);
1066 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1068 started = 1;
1070 if (started) {
1071 if (wPreferences.size_display == WDIS_FRAME_CENTER) {
1072 drawTransparentFrame(wwin, orig_fx, orig_fy,
1073 orig_fw, orig_fh);
1074 moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
1075 drawTransparentFrame(wwin, fx, fy, fw, fh);
1076 } else {
1077 drawTransparentFrame(wwin, orig_fx, orig_fy,
1078 orig_fw, orig_fh);
1079 drawTransparentFrame(wwin, fx, fy, fw, fh);
1081 if (fh != orig_fh || fw != orig_fw) {
1082 if (wPreferences.size_display == WDIS_NEW) {
1083 showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw,
1084 orig_fy + orig_fh, res);
1086 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1089 break;
1091 case ButtonPress:
1092 break;
1094 case ButtonRelease:
1095 if (event.xbutton.button != ev->xbutton.button)
1096 break;
1098 if (started) {
1099 showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
1101 drawTransparentFrame(wwin, fx, fy, fw, fh);
1103 XUngrabKeyboard(dpy, CurrentTime);
1104 unmapGeometryDisplay(wwin);
1105 XUngrabServer(dpy);
1106 wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
1108 #ifdef DEBUG
1109 puts("End resize window");
1110 #endif
1111 return;
1113 default:
1114 WMHandleEvent(&event);
1119 #undef LEFT
1120 #undef RIGHT
1121 #undef HORIZONTAL
1122 #undef UP
1123 #undef DOWN
1124 #undef VERTICAL
1125 #undef HCONSTRAIN
1126 #undef RESIZEBAR
1128 void
1129 wUnselectWindows(WScreen *scr)
1131 WWindow *wwin;
1133 while (scr->selected_windows) {
1134 wwin = scr->selected_windows->head;
1135 if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
1136 wIconSelect(wwin->icon);
1138 wSelectWindow(wwin, False);
1143 static void
1144 selectWindowsInside(WScreen *scr, int x1, int y1, int x2, int y2)
1146 WWindow *tmpw;
1148 /* select the windows and put them in the selected window list */
1149 tmpw = scr->focused_window;
1150 while (tmpw != NULL) {
1151 if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
1152 if ((tmpw->frame->workspace == scr->current_workspace
1153 || tmpw->window_flags.omnipresent)
1154 && (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1)
1155 && (tmpw->frame->core->width + tmpw->frame_x <= x2)
1156 && (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
1157 wSelectWindow(tmpw, True);
1160 tmpw = tmpw->prev;
1165 void
1166 wSelectWindows(WScreen *scr, XEvent *ev)
1168 XEvent event;
1169 Window root = scr->root_win;
1170 GC gc = scr->frame_gc;
1171 int xp = ev->xbutton.x_root;
1172 int yp = ev->xbutton.y_root;
1173 int w = 0, h = 0;
1174 int x = xp, y = yp;
1176 #ifdef DEBUG
1177 puts("Selecting windows");
1178 #endif
1179 if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
1180 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
1181 GrabModeAsync, None, wCursor[WCUR_DEFAULT],
1182 CurrentTime) != Success) {
1183 return;
1185 XGrabServer(dpy);
1187 wUnselectWindows(scr);
1189 XDrawRectangle(dpy, root, gc, xp, yp, w, h);
1190 while (1) {
1191 WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask
1192 | ButtonPressMask, &event);
1194 switch (event.type) {
1195 case MotionNotify:
1196 XDrawRectangle(dpy, root, gc, x, y, w, h);
1197 x = event.xmotion.x_root;
1198 if (x < xp) {
1199 w = xp - x;
1200 } else {
1201 w = x - xp;
1202 x = xp;
1204 y = event.xmotion.y_root;
1205 if (y < yp) {
1206 h = yp - y;
1207 } else {
1208 h = y - yp;
1209 y = yp;
1211 XDrawRectangle(dpy, root, gc, x, y, w, h);
1212 break;
1214 case ButtonPress:
1215 break;
1217 case ButtonRelease:
1218 if (event.xbutton.button != ev->xbutton.button)
1219 break;
1221 XDrawRectangle(dpy, root, gc, x, y, w, h);
1222 XUngrabServer(dpy);
1223 XUngrabPointer(dpy, CurrentTime);
1224 selectWindowsInside(scr, x, y, x + w, y + h);
1225 #ifdef DEBUG
1226 puts("End window selection");
1227 #endif
1228 return;
1230 default:
1231 WMHandleEvent(&event);
1237 void
1238 InteractivePlaceWindow(WWindow *wwin, int *x_ret, int *y_ret,
1239 unsigned width, unsigned height)
1241 WScreen *scr = wwin->screen_ptr;
1242 Window root = scr->root_win;
1243 int x, y, h = 0;
1244 XEvent event;
1245 KeyCode shiftl, shiftr;
1246 Window junkw;
1247 int junk;
1249 if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
1250 GrabModeAsync, GrabModeAsync, None,
1251 wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
1252 *x_ret = 0;
1253 *y_ret = 0;
1254 return;
1256 if (!wwin->window_flags.no_titlebar) {
1257 h = scr->title_font->height + TITLEBAR_EXTRA_HEIGHT;
1258 height += h;
1260 if (!wwin->window_flags.no_resizebar) {
1261 height += RESIZEBAR_HEIGHT;
1263 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1264 XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk,
1265 (unsigned *) &junk);
1266 mapPositionDisplay(wwin, x - width/2, y - h/2, width, height);
1268 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1270 shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
1271 shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
1272 while (1) {
1273 WMMaskEvent(dpy, PointerMotionMask|ButtonPressMask|ExposureMask|KeyPressMask,
1274 &event);
1275 switch (event.type) {
1276 case KeyPress:
1277 if ((event.xkey.keycode == shiftl)
1278 || (event.xkey.keycode == shiftr)) {
1279 drawTransparentFrame(wwin,
1280 x - width/2, y - h/2, width, height);
1281 cyclePositionDisplay(wwin,
1282 x - width/2, y - h/2, width, height);
1283 drawTransparentFrame(wwin,
1284 x - width/2, y - h/2, width, height);
1286 break;
1288 case MotionNotify:
1289 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1291 x = event.xmotion.x_root;
1292 y = event.xmotion.y_root;
1294 if (wPreferences.move_display == WDIS_FRAME_CENTER)
1295 moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
1297 showPosition(wwin, x - width/2, y - h/2);
1299 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1301 break;
1303 case ButtonPress:
1304 drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
1305 XSync(dpy, 0);
1306 *x_ret = x - width/2;
1307 *y_ret = y - h/2;
1308 XUngrabPointer(dpy, CurrentTime);
1309 XUngrabKeyboard(dpy, CurrentTime);
1310 /* get rid of the geometry window */
1311 unmapPositionDisplay(wwin);
1312 return;
1314 default:
1315 WMHandleEvent(&event);
1316 break;