/*
 *  WindowMaker window manager
 * 
 *  Copyright (c) 1997 Alfredo K. Kojima
 * 
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include "wconfig.h"

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <stdio.h>
#include <unistd.h>

#include "generic/wwmlib.h"
#include "WindowMaker.h"
#include "wcore.h"
#include "window.h"
#include "client.h"
#include "icon.h"
#include "funcs.h"
#include "actions.h"

/****** Global Variables ******/
extern Time LastTimestamp;

extern Cursor wCursor[WCUR_LAST];

extern WPreferences wPreferences;

extern Atom _XA_WM_PROTOCOLS;
#if 0
extern Atom _XA_GNUSTEP_WM_RESIZE_WINDOW;
extern Atom _XA_GNUSTEP_WM_RESIZED_WINDOW;
#endif

/** Locals **/
static LinkedList *wSelectedWindows=NULL;


static void
showPosition(WWindow *wwin, int x, int y)
{
    WScreen *scr=wwin->screen_ptr;
    GC gc = scr->info_text_gc;
    char num[64];
    int fw;

    fw = MyTextWidth(scr->info_text_font.font, "8888x8888", 9);
    XClearWindow(dpy, scr->geometry_display);
    sprintf(num, "%4i x %4i", x, y);
#ifdef I18N_MB
    XmbDrawString(dpy, scr->geometry_display, scr->info_text_font.font, gc, 
		  (80-fw)/2, scr->info_text_font.y+4, num, strlen(num));
#else
    XDrawString(dpy, scr->geometry_display, gc, (80-fw)/2, 
		scr->info_text_font.y+4, num, strlen(num));
#endif
}

static void
doWindowMove(WWindow *wwin, LinkedList *list, int dx, int dy)
{
    WWindow *tmpw;
    int x, y;
    int scr_width = wwin->screen_ptr->scr_width;
    int scr_height = wwin->screen_ptr->scr_height;

    if (!list) {
	wWindowConfigure(wwin, wwin->frame_x+dx, wwin->frame_y+dy, 
			 wwin->frame->width, wwin->frame->height);
    } else {
	while (list) {
	    tmpw = list->head;
	    x = tmpw->frame_x + dx;
	    y = tmpw->frame_y + dy;
	    /* don't let windows become unreachable */
	    
	    if (x + (int)tmpw->frame->width < 20)
	      x = 20 - tmpw->frame->width;
	    else if (x + 20 > scr_width)
	      x = scr_width - 20;
	    
	    if (y + (int)tmpw->frame->height < 20)
	      y = 0;
	    else if (y + 20 > scr_height)
	      y = scr_height - 20;
	    
 	    wWindowConfigure(tmpw, x, y, tmpw->frame->width, 
			     tmpw->frame->height);
	    list = list->tail;
	}
    }
}

static void
drawFrames(WWindow *wwin, LinkedList *list, int dx, int dy)
{
    WWindow *tmpw;
    int scr_width = wwin->screen_ptr->scr_width;
    int scr_height = wwin->screen_ptr->scr_height;
    Window root = wwin->screen_ptr->root_win;
    GC gc = wwin->screen_ptr->frame_gc;
    int x, y, h=0;

    if (wwin->window_flags.titlebar && !wwin->flags.shaded) {
        h = wwin->screen_ptr->title_font.height + 8;   
    }
 
    if (!list) {
	XDrawRectangle(dpy, root, gc, wwin->frame_x+dx, wwin->frame_y+dy,
		       wwin->frame->width, wwin->frame->height);

	if (h) {
           XDrawLine(dpy, root, gc, wwin->frame_x+dx, wwin->frame_y+dy+h,
		     wwin->frame->width+wwin->frame_x+dx,wwin->frame_y+dy+h); 
	}

    } else {
	while (list) {
	    tmpw = list->head;
	    x = tmpw->frame_x + dx;
	    y = tmpw->frame_y + dy;
	    
	    /* don't let windows become unreachable */
	    
	    if (x + (int)tmpw->frame->width < 20)
	      x = 20 - tmpw->frame->width;
	    else if (x + 20 > scr_width)
	      x = scr_width - 20;
	    
	    if (y + (int)tmpw->frame->height < 20)
	      y = 0;
	    else if (y + 20 > scr_height)
	      y = scr_height - 20;

	    XDrawRectangle(dpy, root, gc, x, y,tmpw->frame->width, 
			   tmpw->frame->height);
            if (h) {
               XDrawLine(dpy, root, gc,x,y+h, tmpw->frame->width+x,y+h);
	    } 
	    list = list->tail;
	}
    }
}


static void
flushMotion()
{
    XEvent ev;

    XSync(dpy, 0);
    while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev));
}

/*
 *---------------------------------------------------------------------- 
 * wMouseMoveWindow--
 * 	Move the named window and the other selected ones (if any),
 * interactively. Also shows the position of the window, if only one
 * window is being moved.
 * 	If the window is not on the selected window list, the selected
 * windows are deselected.
 * 	If shift is pressed during the operation, the position display
 * is changed to another type.
 * 
 * Returns:
 * 	True if the window was moved, False otherwise.
 * 
 * Side effects:
 * 	The window(s) position is changed, and the client(s) are 
 * notified about that.
 * 	The position display configuration may be changed.
 *---------------------------------------------------------------------- 
 */
int
wMouseMoveWindow(WWindow *wwin, XEvent *ev)
{
    WScreen *scr=wwin->screen_ptr;
    XEvent event;
    Window root = scr->root_win;
    KeyCode shiftl, shiftr;
    int w = wwin->frame->width;
    int h = wwin->frame->height;
    int x = wwin->frame_x;
    int y = wwin->frame_y;
    int ox, oy, orig_x, orig_y;
    short count=0;		       /* for automatic workspace creation */
    int started=0;
    int warped=0;

    if (!wwin->flags.selected) {
	/* this window is not selected, unselect others and move only wwin */
	wUnselectWindows();
    }
    orig_x = ox = ev->xbutton.x_root;
    orig_y = oy = ev->xbutton.y_root;
#ifdef DEBUG
    puts("Moving window");
#endif
    shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
    shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
    while(1) {
	if (warped) {
	    int junk;
	    Window junkw;
	    /* XWarpPointer() doesn't seem to generate Motion events,
	     * so we've got to simulate them */
	    XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
			  &event.xmotion.y_root, &junk, &junk,
			  (unsigned *)&junk);
	} else {
	    XMaskEvent(dpy, KeyPressMask|ButtonMotionMask|ButtonReleaseMask
		       |ExposureMask, &event);
	}
	switch (event.type) {
	 case KeyPress:
	    if (wSelectedWindows)
	      break;
	    showPosition(wwin, x, y);
	    if ((event.xkey.keycode == shiftl) 
		|| (event.xkey.keycode == shiftr)) {
		if (!wPreferences.opaque_move)
		  drawFrames(wwin, wSelectedWindows, ox-orig_x, oy-orig_y);
		if (wPreferences.move_display==3)
		  wPreferences.move_display=0;
		else
		  wPreferences.move_display++;
		
		if (wPreferences.move_display == WDIS_NEW) {
		    XUnmapWindow(dpy, scr->geometry_display);
		} else {
		    if (wPreferences.move_display == WDIS_CENTER) {
			XMoveWindow(dpy, scr->geometry_display,
				    (scr->scr_width-80)/2,
				    (scr->scr_height-20)/2);
		    } else if (wPreferences.move_display == WDIS_TOPLEFT) {
			XMoveWindow(dpy, scr->geometry_display, 1, 1);
		    } else if (wPreferences.move_display==WDIS_FRAME_CENTER) {
			XMoveWindow(dpy, scr->geometry_display, x+w/2, y+h/2);
		    }
		    XMapRaised(dpy, scr->geometry_display);
		    showPosition(wwin, x, y);
		}
		if (!wPreferences.opaque_move)
		  drawFrames(wwin, wSelectedWindows, ox-orig_x, oy-orig_y);
	    }
	    showPosition(wwin, x, y);
	    break;

	 case MotionNotify:
	    if (started) {
		if (!wSelectedWindows) {
		    showPosition(wwin, x, y);
		}
		if (!wPreferences.opaque_move)
		  drawFrames(wwin, wSelectedWindows, ox-orig_x, oy-orig_y);
		else
		  doWindowMove(wwin,wSelectedWindows,event.xmotion.x_root-ox,
			       event.xmotion.y_root-oy);
		x += event.xmotion.x_root - ox;
		y += event.xmotion.y_root - oy;

		if (!wSelectedWindows 
		    && wPreferences.move_display==WDIS_FRAME_CENTER) {
		    XMoveWindow(dpy, scr->geometry_display, 
				x+(w-80)/2, y+(h-20)/2);
		}

		if (!warped && wPreferences.autowrap) {

		    if (event.xmotion.x_root < 1 && scr->workspace>0) {
			int a=0;
			
			/* do not let window be unmapped */
			if (wPreferences.opaque_move) {
			    a = wwin->window_flags.omnipresent;
			    wwin->window_flags.omnipresent = 1;
			}

			/* go to previous workspace */
			wChangeWorkspace(scr, scr->workspace-1);

			RefreshWorkspaceMenu(scr);
			
			if (wPreferences.opaque_move) {
			    wwin->window_flags.omnipresent = a;

			    wWindowChangeWorkspace(wwin, scr->workspace);
			}
			XWarpPointer(dpy, None, None, 0, 0, 0, 0, 
				     scr->scr_width-20, 0);
			flushMotion();
			warped = 1;
			
			count = 0;
		    } else if (event.xmotion.x_root >= scr->scr_width-1) {
			
			/* if user insists on trying to go to next workspace
			 * even when it's already the last, create
			 * a new one */
			 if (scr->workspace == scr->last_workspace
			     && scr->last_workspace < MAX_WORKSPACES) {
			     
			     if (ox == event.xmotion.x_root) {
				 
				 /* detect user "rubbing" the window against
				  * the edge */
				 if (count>0 
				     && oy-event.xmotion.y_root>MOVE_THRESHOLD)
				   count = -(count+1);
				 else if (count<=0 
					  && event.xmotion.y_root-oy>MOVE_THRESHOLD)
				   count = -count + 1;
			     }
			     /* create a new workspace */
			     if (abs(count) > 3) {
			     int a=0;
		    
				 /* go to next workspace */
				 if (wPreferences.opaque_move) {
				     a = wwin->window_flags.omnipresent;
				     wwin->window_flags.omnipresent=1;
				 }

				 count = 0;
				 
				 wNewWorkspace(scr);
				 
				 RefreshWorkspaceMenu(scr);
				 
				 if (wPreferences.opaque_move) {
				     wwin->window_flags.omnipresent=a;

				     wWindowChangeWorkspace(wwin, 
							    scr->workspace);
				 }
				 
				 XWarpPointer(dpy, None, None, 0, 0, 0, 0, 
					      -(scr->scr_width-20), 0);
				 flushMotion();
				 warped = 1;
			     }
			 } else if (scr->workspace < scr->last_workspace) {
			     int a=0;
		    
			     /* go to next workspace */
			     if (wPreferences.opaque_move) {
				 a = wwin->window_flags.omnipresent;
				 wwin->window_flags.omnipresent=1;
			     }

			     wChangeWorkspace(scr, scr->workspace+1);
			     
			     RefreshWorkspaceMenu(scr);

			     if (wPreferences.opaque_move) {
				 wwin->window_flags.omnipresent=a;
			     
				 wWindowChangeWorkspace(wwin, scr->workspace);
			     }
			     XWarpPointer(dpy, None, None, 0, 0, 0, 0,
					  -(scr->scr_width-20), 0);
			     flushMotion();
			     warped = 1;
			 }
		    } else {
			count = 0;
		    }
		} else {
		    warped = 0;
		}
	    } else if (abs(orig_x-event.xmotion.x_root)>=MOVE_THRESHOLD
		       || abs(orig_y-event.xmotion.y_root)>=MOVE_THRESHOLD) {
		XChangeActivePointerGrab(dpy, ButtonMotionMask
					 |ButtonReleaseMask,
					 wCursor[WCUR_MOVE], CurrentTime);
		started=1;
		XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, 
			      CurrentTime);
		if (wPreferences.opaque_move) {
		    event.xmotion.x_root = orig_x;
		    event.xmotion.y_root = orig_y;
		}
		if (!wSelectedWindows) {
		    if (wPreferences.move_display == WDIS_TOPLEFT) {
			XMoveWindow(dpy, scr->geometry_display, 
				    1, 1);
		    }
		    XMapRaised(dpy, scr->geometry_display);
		    showPosition(wwin, x, y);
		}
		if (!wPreferences.opaque_move) 
		  XGrabServer(dpy);
	    }

	    ox = event.xmotion.x_root;
	    oy = event.xmotion.y_root;
	    
	    if (started && !wPreferences.opaque_move)
	      drawFrames(wwin, wSelectedWindows, ox-orig_x, oy-orig_y);
	    break;
	    
	 case ButtonRelease:
	    if (started) {
		if (!wPreferences.opaque_move) {
		    drawFrames(wwin, wSelectedWindows, ox-orig_x, oy-orig_y);
		    
		    XSync(dpy, 0);
		    doWindowMove(wwin, wSelectedWindows, ox-orig_x, oy-orig_y);
		}
		XUngrabKeyboard(dpy, CurrentTime);
		if (!wPreferences.opaque_move) {
		    XUngrabServer(dpy);
		    wWindowChangeWorkspace(wwin, scr->workspace);
		    wSetFocusTo(scr, wwin);
		}
		if (!wSelectedWindows) {
		    /* get rid of the geometry window */
		    XUnmapWindow(dpy, scr->geometry_display);
		}
	    }
#ifdef DEBUG
	    puts("End move window");
#endif
	    return started;
	    
	 default:
	    DispatchEvent(&event);
	    break;
	}
    }
    return 0;
}
 
#define LEFT	1
#define RIGHT	2
#define VERT	4




static int
getResizeDirection(WWindow  *wwin, int x, int y)
{
    int w = wwin->resizebar->width - 1;
    int cw = wwin->resizebar_corner_width;

    if (cw*2>=w) {
	if (x < cw)
	  return (LEFT|VERT);
	else
	  return (RIGHT|VERT);
    }
    if ((x > cw) && (x < w - cw))
      return VERT;
    if (x < cw - 20)
      return LEFT;
    else {	
	if (x < cw)
	  return (VERT|LEFT);
    }    
    if (x > w - (cw - 20))
      return RIGHT;
    return (RIGHT|VERT);
}


static void
showGeometry(WWindow *wwin, int x1, int y1, int x2, int y2, int direction)
{
    WScreen *scr=wwin->screen_ptr;
    Window root = scr->root_win;
    GC gc = scr->line_gc;
    int ty, by, my, x, y, mx, s;
    char num[64];
    XSegment segment[4];
    int fw, fh=scr->info_text_font.height;

    ty = y1+wwin->top_width;
    by = y2-wwin->bottom_width;
    fw = MyTextWidth(scr->info_text_font.font, "8888x8888", 9);
    if (wPreferences.size_display==WDIS_NEW) {
	/* vertical geometry */
	if (((direction & LEFT) && (x2<scr->scr_width-fw)) || (x1<fw)) {
	    x = x2;
	    s = -15;
	} else {
	    x = x1;
	    s = 15;
	}
	my = y1+(by-ty)/2+scr->info_text_font.y;
    
	segment[0].x1 = x-s-2;
	segment[0].y1 = ty;
	segment[0].x2 = x-(s-7);
	segment[0].y2 = ty;
	
	segment[1].x1 = x-(s-2);
	segment[1].y1 = ty;
	segment[1].x2 = x-(s-5);
	segment[1].y2 = ty+6;
	
	segment[2].x1 = x-(s-2);
	segment[2].y1 = ty;
	segment[2].x2 = x-s;
	segment[2].y2 = ty+6;

	segment[3].x1 = x-(s-2);
	segment[3].y1 = ty;
	segment[3].x2 = x-(s-2);
	segment[3].y2 = my;

	XDrawSegments(dpy, root, gc, segment, 4);
	segment[0].y1 = by;
	segment[0].y2 = by;
	
	segment[1].y1 = by;
	segment[1].y2 = by-6;
	
	segment[2].y1 = by;
	segment[2].y2 = by-6;
	
	segment[3].y1 = my+fh;
	segment[3].y2 = by;
	XDrawSegments(dpy, root, gc, segment, 4);

	sprintf(num, "%i", (by-ty)/wwin->normal_hints->height_inc);
	fw = MyTextWidth(scr->info_text_font.font, num, strlen(num));
#ifdef I18N_MB
	XmbDrawString(dpy, root, scr->info_text_font.font, gc, x-(s-2)-fw/2, 
		      my + scr->info_text_font.y + 1, num, strlen(num));
#else
	XDrawString(dpy, root, gc, x-(s-2)-fw/2, 
		    my + scr->info_text_font.y + 1, num, strlen(num));
#endif	
	/* horizontal geometry */
	if (y1<15) {
	    y = y2;
	    s = -15;
	} else {
	    y = y1;
	    s = 15;
	}
	mx = x1 + (x2-x1)/2;
	sprintf(num, "%i", (x2-x1)/wwin->normal_hints->width_inc);
	fw = MyTextWidth(scr->info_text_font.font, num, strlen(num));
	segment[0].x1 = x1;
	segment[0].y1 = y-s-2;
	segment[0].x2 = x1;
	segment[0].y2 = y-(s-7);
	
	segment[1].x1 = x1+6;
	segment[1].y1 = y-s;
	segment[1].x2 = x1;
	segment[1].y2 = y-(s-2);
	
	segment[2].x1 = x1;
	segment[2].y1 = y-(s-2);
	segment[2].x2 = x1+6;
	segment[2].y2 = y-(s-5);
	
	segment[3].x1 = x1;
	segment[3].y1 = y-(s-2);
	segment[3].x2 = mx-fw/2;
	segment[3].y2 = y-(s-2);
	XDrawSegments(dpy, root, gc, segment, 4);
	
	segment[0].x1 = x2;
	segment[0].x2 = x2;
	
	segment[1].x1 = x2-6;
	segment[1].x2 = x2;
	
	segment[2].x1 = x2;
	segment[2].x2 = x2-6;
	
	segment[3].x1 = mx+fw/2;
	segment[3].x2 = x2;
	XDrawSegments(dpy, root, gc, segment, 4);
#ifdef I18N_MB
	XmbDrawString(dpy, root, scr->info_text_font.font, gc,
		      mx-fw/2, y-(s-2)+fh/2, num, strlen(num));
#else
	XDrawString(dpy, root, gc, mx-fw/2, y-(s-2)+fh/2, num, strlen(num));
#endif
    } else {
	XClearWindow(dpy, scr->geometry_display);
	sprintf(num, "%4i x %4i", (by-ty-wwin->normal_hints->base_height)
		/wwin->normal_hints->height_inc,
		(x2-x1-wwin->normal_hints->base_width)
		/wwin->normal_hints->width_inc);
#ifdef I18N_MB
	XmbDrawString(dpy, scr->geometry_display, scr->info_text_font.font,
		      scr->info_text_gc,(80-fw)/2, scr->info_text_font.y+4,
		      num, strlen(num));
#else
	XDrawString(dpy, scr->geometry_display, scr->info_text_gc, (80-fw)/2,
		    scr->info_text_font.y+4, num, strlen(num));
#endif
    }
}


void
wMouseResizeWindow(WWindow  *wwin, XEvent *ev)
{
    XEvent event;
    WScreen *scr=wwin->screen_ptr;
    Window root = scr->root_win;
    GC gc = scr->frame_gc;
    int vert_border = wwin->top_width + wwin->bottom_width;    
    int fw = wwin->frame->width;
    int fh = wwin->frame->height;
    int fx = wwin->frame_x;
    int fy = wwin->frame_y;
    int dragx, dragy;
    int ox, oy;
    int dw, dh;
    int rw=fw, rh=fh;
    int rx1, ry1, rx2, ry2;
    int res=0;
    Window junkw;
    int junk;
    KeyCode shiftl, shiftr;
    int h=0;
    
    XQueryPointer(dpy, root, &junkw, &junkw, &ox, &oy, &junk, &junk, 
		  (unsigned *)&junk);
    ox = -ox;
    
#ifdef DEBUG
    puts("Resizing window");
#endif

    wUnselectWindows();
    rx1 = fx;
    rx2 = fx + fw - 1;
    ry1 = fy;
    ry2 = fy + fh - 1;
    ox = -1;
    shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
    shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
    h = wwin->screen_ptr->title_font.height + 8;
    while(1) {
	XMaskEvent(dpy, KeyPressMask|ButtonMotionMask|ButtonReleaseMask
		   |ExposureMask, &event);
	switch (event.type) {
	 case KeyPress:
	    showGeometry(wwin, fx, fy, fx+fw, fy+fh, res);
	    if ((event.xkey.keycode == shiftl) 
		|| (event.xkey.keycode == shiftr)) {
		XDrawRectangle(dpy, root, gc, fx+FRAME_BORDER_WIDTH, fy, 
			       fw, fh);
		if (wPreferences.size_display==3)
		  wPreferences.size_display=0;
		else
		  wPreferences.size_display++;
		
		if (wPreferences.size_display == WDIS_NEW) {
		    XUnmapWindow(dpy, wwin->screen_ptr->geometry_display);
		} else {
		    if (wPreferences.size_display == WDIS_CENTER) {
			XMoveWindow(dpy, scr->geometry_display,
				    (scr->scr_width-80)/2, 
				    (scr->scr_height-20)/2);
		    } else if (wPreferences.size_display == WDIS_TOPLEFT) {
			XMoveWindow(dpy, scr->geometry_display, 1, 1);
		    } else if (wPreferences.size_display==WDIS_FRAME_CENTER) {
			XMoveWindow(dpy, scr->geometry_display, fx+(fw-80)/2, 
				    fy+(fh-20)/2);
		    }
		    XMapRaised(dpy, scr->geometry_display);
		    showGeometry(wwin, fx, fy, fx+fw, fy+fh, res);
		}
		XDrawRectangle(dpy, root, gc, fx+FRAME_BORDER_WIDTH, fy, 
			       fw, fh);
	    }
	    showGeometry(wwin, fx, fy, fx+fw, fy+fh, res);
	    break;

	 case MotionNotify:
	    dragx = event.xmotion.x_root;
	    dragy = event.xmotion.y_root;
	    if (ox>=0) {
		showGeometry(wwin, fx, fy, fx+fw, fy+fh, res);
		XDrawRectangle(dpy, root, gc, fx+FRAME_BORDER_WIDTH, fy, 
			       fw, fh);
		if (h>0)
		  XDrawLine(dpy, root, gc, fx+FRAME_BORDER_WIDTH, fy+h, 
			    fw+fx, fy+h);
		dw = dragx - ox;
		dh = dragy - oy;
		if (res & LEFT) {
		    dw = -dw;
		} else if (res & RIGHT) {
		    /* */
		} else { /* vertical only */
		    dw = 0;
		}

		if (!(res & VERT)) {
		    dh = 0;
		}
		rw += dw;
		rh += dh;
		
		fw = rw;
		fh = rh - vert_border;
		wWindowConstrainSize(wwin, &fw, &fh);		
		fh += vert_border;

		if (res & LEFT) {
		    fx = rx2 - fw + 1;
		} else if (res & RIGHT) {
		    fx = rx1;
		}
		fy = ry1;
		if (wPreferences.size_display==WDIS_FRAME_CENTER) {
		    XMoveWindow(dpy, wwin->screen_ptr->geometry_display, 
				fx+(fw-80)/2, fy+(fh-20)/2);
		}
#if 0
		if (wwin->protocols.RESIZE_WINDOW) {
		    wClientSendProtocolMessage(wwin, 
					       _XA_GNUSTEP_WM_RESIZE_WINDOW,
					       event.xbutton.time,fw, 
					       fh-wwin->top_width
					       -wwin->bottom_width);
		}
#endif
	    } else {
		if (wPreferences.size_display!=WDIS_NEW) {
		    if (wPreferences.size_display == WDIS_TOPLEFT) {
			XMoveWindow(dpy, scr->geometry_display, 1, 1);
		    }
		    XMapRaised(dpy, wwin->screen_ptr->geometry_display);
		}
		XTranslateCoordinates(dpy, root, wwin->resizebar->window,
				      event.xmotion.x_root,
				      event.xmotion.y_root, &ox, &oy, &junkw);
		res = getResizeDirection(wwin, ox, oy);
		XChangeActivePointerGrab(dpy, ButtonMotionMask
					 |ButtonReleaseMask,
					 wCursor[WCUR_RESIZE], CurrentTime);
		XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, 
			      CurrentTime);
		
		XGrabServer(dpy);
		 
	    }
	    ox = dragx;
	    oy = dragy;
	    showGeometry(wwin, fx, fy, fx+fw, fy+fh, res);
	    XDrawRectangle(dpy, root, gc, fx+FRAME_BORDER_WIDTH, fy, fw, fh);
	    if (h>0)
	      XDrawLine(dpy, root, gc, fx+FRAME_BORDER_WIDTH, fy+h, 
			fw+fx, fy+h);
	    break;

	 case ButtonRelease:
	    if (ox>=0) {
		showGeometry(wwin, fx, fy, fx+fw, fy+fh, res);
		XDrawRectangle(dpy, root, gc, fx+FRAME_BORDER_WIDTH, fy, 
			       fw, fh);
		if (h>0)
		  XDrawLine(dpy, root, gc, fx+FRAME_BORDER_WIDTH, fy+h, 
			    fw+fx, fy+h);
		XUngrabKeyboard(dpy, CurrentTime);
		XUnmapWindow(dpy, wwin->screen_ptr->geometry_display);
		
		XUngrabServer(dpy);
		wWindowConfigure(wwin, fx, fy, fw, fh);
	    }
#ifdef DEBUG
	    puts("End resize window");
#endif
	    return;
	    
	 default:
	    DispatchEvent(&event);
	}
    }
}
#undef LEFT
#undef RIGHT
#undef VERT



void
wUnselectWindows()
{
    WWindow *wwin;

    while (wSelectedWindows) {
	wwin = wSelectedWindows->head;
	XSetWindowBorder(dpy, wwin->frame->window, 
			 wwin->screen_ptr->black_pixel);
	wwin->flags.selected = 0;
	list_remove_head(&wSelectedWindows);
    }
}


void
wSelectWindow(WWindow *wwin)
{
    if (!wwin->flags.selected) {
	wwin->flags.selected = 1;
	XSetWindowBorder(dpy, wwin->frame->window, 
			 wwin->screen_ptr->white_pixel);
	wSelectedWindows = list_cons(wwin, wSelectedWindows);
    } else {
	wwin->flags.selected = 0;
	XSetWindowBorder(dpy, wwin->frame->window, 
			 wwin->screen_ptr->black_pixel);
	wSelectedWindows = list_remove_elem(wSelectedWindows, wwin);
    }
}



static void
selectWindowsInside(WScreen *scr, int x1, int y1, int x2, int y2)
{
    WWindow *tmpw;

    /* select the windows and put them in the selected window list */
    tmpw = scr->focused_window;
    while (tmpw!=NULL) {
	if (!(tmpw->flags.miniaturized||tmpw->flags.hidden)) {
	    if ((tmpw->workspace == scr->workspace
		 || tmpw->window_flags.omnipresent)
		&& (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1) 
		&& (tmpw->frame->width+tmpw->frame_x <= x2) 
		&& (tmpw->frame->height+tmpw->frame_y <= y2)) {
		XSetWindowBorder(dpy, tmpw->frame->window, 
				 tmpw->screen_ptr->white_pixel);
		tmpw->flags.selected = 1;
		wSelectedWindows=list_cons(tmpw, wSelectedWindows);
	    }
	}
	tmpw = tmpw->prev;
    }
}


void
wSelectWindows(WScreen *scr, XEvent *ev)
{
    XEvent event;
    Window root = scr->root_win;
    GC gc = scr->frame_gc;
    int xp = ev->xbutton.x_root;
    int yp = ev->xbutton.y_root;
    int w=0, h=0;
    int x=xp, y=yp;

#ifdef DEBUG
    puts("Selecting windows");
#endif
    if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
		     |ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, 
		     wCursor[WCUR_DEFAULT], CurrentTime) !=Success) {
	return;
    }
    XGrabServer(dpy);

    wUnselectWindows();

    XDrawRectangle(dpy, root, gc, xp, yp, w, h);
    while(1) {
	XMaskEvent(dpy, ButtonReleaseMask|PointerMotionMask, &event);
	
	switch (event.type) {
	 case MotionNotify:
	    XDrawRectangle(dpy, root, gc, x, y, w, h);
	    x=event.xmotion.x_root;
	    if (x<xp) {
		w = xp-x;
	    } else {
		w = x-xp;
		x = xp;
	    }
	    y=event.xmotion.y_root;
	    if (y<yp) {
		h = yp-y;
	    } else {
		h = y-yp;
		y = yp;
	    }
	    XDrawRectangle(dpy, root, gc, x, y, w, h);
	    break;

	 case ButtonRelease:
	    XDrawRectangle(dpy, root, gc, x, y, w, h);
	    XUngrabServer(dpy);
	    XUngrabPointer(dpy, CurrentTime);
	    selectWindowsInside(scr, x, y, x+w, y+h);
#ifdef DEBUG
	    puts("End window selection");
#endif
	    return;

	 default:
	    DispatchEvent(&event);
	}
    }
}





void
InteractivePlaceWindow(WWindow *wwin, int *x_ret, int *y_ret)
{
    Window root = wwin->screen_ptr->root_win;
    GC gc = wwin->screen_ptr->frame_gc;
    int x, y, h=0;
    int width = wwin->client.width;
    int height = wwin->client.height;
    XEvent event;
    KeyCode shiftl, shiftr;
    Window junkw;
    int junk;

    if (XGrabPointer(dpy, root, False, PointerMotionMask|ButtonPressMask, 
		     GrabModeAsync, GrabModeAsync, None, 
		     wCursor[WCUR_DEFAULT], CurrentTime) !=Success) {
	return;
    }

    if (wwin->window_flags.titlebar) {
	h = wwin->screen_ptr->title_font.height + 8;
	height += h;
    }

    if (wwin->window_flags.resizable) {
	height += RESIZEBAR_HEIGHT;
    }

    XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
    XMapRaised(dpy, wwin->screen_ptr->geometry_display);
    XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk, 
		  (unsigned *)&junk);
    XDrawRectangle(dpy, root, gc, x-width/2, y-h/2, width, height);
    if (h) {
	XDrawLine(dpy, root, gc, x-width/2, y+h/2, x+width/2, y+h/2);
    }
    shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
    shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
    while(1) {
	XMaskEvent(dpy, PointerMotionMask|ButtonPressMask|ExposureMask, 
		   &event);
	switch (event.type) {
	 case KeyPress:
	    showPosition(wwin, x-width/2, y-h/2);
	    if ((event.xkey.keycode == shiftl) 
		|| (event.xkey.keycode == shiftr)) {
		XDrawRectangle(dpy, root, gc, x-width/2, y-h/2,
			       width, height);
		if (h) {
		    XDrawLine(dpy, root, gc, x-width/2, y+h/2, x+width/2, 
			      y+h/2);
		}
		if (wPreferences.move_display==3)
		  wPreferences.move_display=0;
		else
		  wPreferences.move_display++;
		
		if (wPreferences.move_display == WDIS_NEW) {
		    XUnmapWindow(dpy, wwin->screen_ptr->geometry_display);
		} else {
		    WScreen *scr=wwin->screen_ptr;

		    if (wPreferences.move_display == WDIS_CENTER) {
			XMoveWindow(dpy, scr->geometry_display,
				    (scr->scr_width-80)/2,
				    (scr->scr_height-20)/2);
		    } else if (wPreferences.move_display == WDIS_TOPLEFT) {
			XMoveWindow(dpy, scr->geometry_display, 1, 1);
		    } else if (wPreferences.move_display==WDIS_FRAME_CENTER) {
			XMoveWindow(dpy, scr->geometry_display, x-width/2, 
				    y-height/2);
		    }
		    XMapRaised(dpy, scr->geometry_display);
		    showPosition(wwin, x-width/2, y-h/2);
		}
		XDrawRectangle(dpy, root, gc, x-width/2, y-h/2,
			       width, height);
		if (h) {
		    XDrawLine(dpy, root, gc, x-width/2, y+h/2, x+width/2, 
			      y+h/2);
		}
	    }
	    showPosition(wwin, x-width/2, y-h/2);
	    break;


	 case MotionNotify:
	    showPosition(wwin, x-width/2, y-h/2);
	    XDrawRectangle(dpy, root, gc, x-width/2, y-h/2,
			   width, height);
	    if (h) {
		XDrawLine(dpy, root, gc, x-width/2, y+h/2, x+width/2, y+h/2);
	    }
	    if (wPreferences.move_display==WDIS_FRAME_CENTER) {
		XMoveWindow(dpy, wwin->screen_ptr->geometry_display, 
			    x+(width-80)/2, y+(height-20)/2);
	    }
	    x = event.xmotion.x_root;
	    y = event.xmotion.y_root;
	    XDrawRectangle(dpy, root, gc, x-width/2, y-h/2, width, height);
	    if (h) {
		XDrawLine(dpy, root, gc, x-width/2, y+h/2, x+width/2, y+h/2);
	    }
	    break;
	    
	 case ButtonPress:
	    XDrawRectangle(dpy, root, gc, x-width/2, y-h/2, width, height);
	    if (h) {
		XDrawLine(dpy, root, gc, x-width/2, y+h/2, x+width/2, y+h/2);
	    }
	    XSync(dpy, 0);
	    *x_ret = x-width/2;
	    *y_ret = y-h/2;
	    XUngrabPointer(dpy, CurrentTime);
	    XUngrabKeyboard(dpy, CurrentTime);
	    /* get rid of the geometry window */
	    XUnmapWindow(dpy, wwin->screen_ptr->geometry_display);
	    return;
	    
	 default:
	    DispatchEvent(&event);
	    break;
	}
    }
}
