/*
 * Copyright (c) 1997 Guylhem Aznar <guylhem@danmark.linux.eu.org>
 * Copyright (C) 1996 Dan Weeks
 * Copyright (C) 1995 Rob Nation
 *
 * 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 "../../configure.h"
#include "../../src/lib/aftersteplib.h"


#include <stdio.h>
#include <signal.h>
#include <string.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xproto.h>
#include <X11/Xatom.h>
#include <X11/Intrinsic.h>
#include <X11/xpm.h>

#include "../../src/afterstep.h"
#include "Pager.h"
extern ScreenInfo Scr;
extern Display *dpy;

Pixel back_pix, fore_pix, hi_pix;
Pixel focus_pix;
Pixel focus_fore_pix;
extern int window_w, window_h, window_x, window_y, usposition, uselabel;
extern int StartIconic;
extern int icon_w, icon_h, icon_x, icon_y;
XFontStruct *font, *windowFont;

GC NormalGC, HiliteGC, rvGC;
GC StdGC, FocusGC;

extern int StickyIcons;
extern PagerWindow *Start;
extern PagerWindow *FocusWin;
static Atom wm_del_win;

extern char *MyName;
extern char defaultbgfile[10][511];

extern int desk1, desk2, ndesks;
extern int TitleAlign;
extern int Rows, Columns;
extern int fd[2];

int desk_w = 0;
int desk_h = 0;
int scr_w = 0;
int scr_h = 0;
int label_h = 0;

DeskInfo *Desks;
int Wait = 0;
XErrorHandler ASErrorHandler(Display *, XErrorEvent *);


/* assorted gray bitmaps for decorative borders */
#define g_width 2
#define g_height 2
static char g_bits[] =
{0x02, 0x01};

#define l_g_width 4
#define l_g_height 2
static char l_g_bits[] =
{0x08, 0x02};

#define s_g_width 4
#define s_g_height 4
static char s_g_bits[] =
{0x01, 0x02, 0x04, 0x08};


Window icon_win;		/* icon window */

/***********************************************************************
 *
 *  Procedure:
 *	Initialize_pager - creates the pager window, if needed
 *
 *  Inputs:
 *	x,y location of the window
 *
 ***********************************************************************/
char *pager_name = "AfterStep Pager";
XSizeHints sizehints =
{
	(PMinSize | PResizeInc | PBaseSize | PWinGravity),
	0, 0, 100, 100,		/* x, y, width and height */
	1, 1,			/* Min width and height */
	0, 0,			/* Max width and height */
	1, 1,			/* Width and height increments */
	{0, 0},
	{0, 0},			/* Aspect ratio - not used */
	1, 1,			/* base size */
	(NorthWestGravity)	/* gravity */
};

void initialize_pager(void)
{
	XTextProperty name;
	unsigned long valuemask;
	XSetWindowAttributes attributes;
	XWMHints wmhints;
	extern char *PagerFore, *PagerBack, *HilightC;
	extern char *font_string, *smallFont;
	extern char *HiBack;
	extern char *HiFore;
	int n, m, w, h, i, l, x, y;
	XGCValues gcv;
	unsigned long gcm;
	XClassHint class1;

	XSetErrorHandler((XErrorHandler) ASErrorHandler);
	wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False);

	n = Scr.VxMax / Scr.MyDisplayWidth;
	m = Scr.VyMax / Scr.MyDisplayHeight;

	/* load the font */
	if ((font = XLoadQueryFont(dpy, font_string)) == NULL) {
		if ((font = XLoadQueryFont(dpy, "fixed")) == NULL) {
			fprintf(stderr, "%s: No fonts available\n", MyName);
			exit(1);
		}
	};
	if (uselabel)
		label_h = font->ascent + font->descent + 2;
	else
		label_h = 0;


	if (smallFont != NULL) {
		windowFont = XLoadQueryFont(dpy, smallFont);
	} else
		windowFont = NULL;

	/* Load the colors */
	fore_pix = GetColor(PagerFore);
	back_pix = GetColor(PagerBack);
	focus_pix = GetColor(HiBack);

	focus_fore_pix = GetColor(HiFore);
	hi_pix = GetColor(HilightC);

	/* Load pixmaps for mono use */
	if (Scr.d_depth < 2) {
		Scr.gray_pixmap =
		    XCreatePixmapFromBitmapData(dpy, Scr.Root, g_bits, g_width, g_height,
					fore_pix, back_pix, Scr.d_depth);
		Scr.light_gray_pixmap =
		    XCreatePixmapFromBitmapData(dpy, Scr.Root, l_g_bits, l_g_width, l_g_height,
					fore_pix, back_pix, Scr.d_depth);
		Scr.sticky_gray_pixmap =
		    XCreatePixmapFromBitmapData(dpy, Scr.Root, s_g_bits, s_g_width, s_g_height,
					fore_pix, back_pix, Scr.d_depth);
	}
	/* Size the window */
	if (Rows < 0) {
		if (Columns < 0) {
			Columns = ndesks;
			Rows = 1;
		} else {
			Rows = ndesks / Columns;
			if (Rows * Columns < ndesks)
				Rows++;
		}
	}
	if (Columns < 0) {
		Columns = ndesks / Rows;
		if (Rows * Columns < ndesks)
			Columns++;
	}
	if (Rows * Columns < ndesks)
		Rows = ndesks / Columns;
	if (window_w > 0) {
		window_w = ((window_w - n) / (n + 1)) * (n + 1) + n;
		Scr.VScale = (Scr.VxMax + Scr.MyDisplayWidth) / window_w;
	}
	if (window_h > 0) {
		window_h = ((window_h - m) / (m + 1)) * (m + 1) + m;
		Scr.VScale = (Scr.VyMax + Scr.MyDisplayHeight) / (window_h - label_h);
	}
	if (window_w <= 0)
		window_w = Columns * ((Scr.VxMax + Scr.MyDisplayWidth) / Scr.VScale + n) +
		    Columns - 1;
	if (window_h <= 0)
		window_h = Rows * ((Scr.VyMax + Scr.MyDisplayHeight) / Scr.VScale
				   + m + label_h + 1) - 2;

	if (window_x < 0) {
		sizehints.win_gravity = NorthEastGravity;
		window_x = Scr.MyDisplayWidth - window_w + window_x - 2;
	}
	if (window_y < 0) {
		window_y = Scr.MyDisplayHeight - window_h + window_y - 2;
		if (sizehints.win_gravity == NorthEastGravity)
			sizehints.win_gravity = SouthEastGravity;
		else
			sizehints.win_gravity = SouthWestGravity;
	}
	if (usposition)
		sizehints.flags |= USPosition;

	valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
	attributes.background_pixel = back_pix;
	attributes.border_pixel = fore_pix;
	attributes.event_mask = (StructureNotifyMask);
	sizehints.width = window_w;
	sizehints.height = window_h;
	sizehints.x = window_x;
	sizehints.y = window_y;
	sizehints.width_inc = Columns * (n + 1);
	sizehints.height_inc = Rows * (m + 1);
	sizehints.base_width = Columns * n + Columns - 1;
	sizehints.base_height = Rows * (m + label_h + 1) - 2;
	sizehints.min_width = Columns * n + Columns - 1;
	sizehints.min_height = Rows * (m + label_h + 1) - 2;

	Scr.Pager_w = XCreateWindow(dpy, Scr.Root, window_x, window_y, window_w,
				    window_h, (unsigned int) 1,
				    CopyFromParent, InputOutput,
				    (Visual *) CopyFromParent,
				    valuemask, &attributes);
	XSetWMProtocols(dpy, Scr.Pager_w, &wm_del_win, 1);
	XSetWMNormalHints(dpy, Scr.Pager_w, &sizehints);

	if ((desk1 == desk2) && (Desks[0].label != NULL))
		XStringListToTextProperty(&Desks[0].label, 1, &name);
	else
		XStringListToTextProperty(&pager_name, 1, &name);

	attributes.event_mask = (StructureNotifyMask | ExposureMask);
	if (icon_w < 1)
		icon_w = (window_w - Columns + 1) / Columns;
	if (icon_h < 1)
		icon_h = (window_h - Rows * label_h - Rows + 1) / Rows;

	icon_w = (icon_w / (n + 1)) * (n + 1) + n;
	icon_h = (icon_h / (m + 1)) * (m + 1) + m;
	icon_win = XCreateWindow(dpy, Scr.Root, window_x, window_y,
				 icon_w, icon_h,
				 (unsigned int) 1,
				 CopyFromParent, InputOutput,
				 (Visual *) CopyFromParent,
				 valuemask, &attributes);
	XGrabButton(dpy, 1, AnyModifier, icon_win,
	    True, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
		    GrabModeAsync, GrabModeAsync, None,
		    None);
	XGrabButton(dpy, 2, AnyModifier, icon_win,
	    True, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
		    GrabModeAsync, GrabModeAsync, None,
		    None);
	XGrabButton(dpy, 3, AnyModifier, icon_win,
	    True, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
		    GrabModeAsync, GrabModeAsync, None,
		    None);
	if (!StartIconic)
		wmhints.initial_state = NormalState;
	else
		wmhints.initial_state = IconicState;
	wmhints.flags = 0;
	if (icon_x > -10000) {
		if (icon_x < 0)
			icon_x = Scr.MyDisplayWidth + icon_x - icon_w;
		if (icon_y > -10000) {
			if (icon_y < 0)
				icon_y = Scr.MyDisplayHeight + icon_y - icon_h;
		} else
			icon_y = 0;
		wmhints.icon_x = icon_x;
		wmhints.icon_y = icon_y;
		wmhints.flags = IconPositionHint;
	}
	wmhints.icon_window = icon_win;
	wmhints.input = False;

	wmhints.flags |= InputHint | StateHint | IconWindowHint;

	class1.res_name = MyName;
	class1.res_class = "ASModule";

	XSetWMProperties(dpy, Scr.Pager_w, &name, &name, NULL, 0,
			 &sizehints, &wmhints, &class1);
	XFree((char *) name.value);

	for (i = 0; i < ndesks; i++) {
		w = window_w / ndesks;
		h = window_h;
		x = w * i;
		y = 0;

		valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
		attributes.background_pixel = back_pix;
		attributes.border_pixel = fore_pix;
		attributes.event_mask = (ExposureMask | ButtonReleaseMask);
		Desks[i].title_w = XCreateWindow(dpy, Scr.Pager_w, x, y, w, h, 1,
						 CopyFromParent,
					     InputOutput, CopyFromParent,
						 valuemask,
						 &attributes);
		attributes.event_mask = (ExposureMask | ButtonReleaseMask |
				     ButtonPressMask | ButtonMotionMask);
		desk_h = window_h - label_h;
		Desks[i].w = XCreateWindow(dpy, Desks[i].title_w, x, y, w, desk_h, 1,
					   CopyFromParent,
					   InputOutput, CopyFromParent,
					   valuemask, &attributes);


		attributes.event_mask = 0;
		attributes.background_pixel = hi_pix;



		w = (window_w - n) / (n + 1);
		h = (window_h - label_h - m) / (m + 1);

		Desks[i].CPagerWin[0] = XCreateWindow(dpy, Desks[i].w, -1000, -1000, w + 6, 3, 0,
			     CopyFromParent, InputOutput, CopyFromParent,
						 valuemask, &attributes);
		Desks[i].CPagerWin[1] = XCreateWindow(dpy, Desks[i].w, -1000, -1000, w + 6, 3, 0,
			     CopyFromParent, InputOutput, CopyFromParent,
						 valuemask, &attributes);

		Desks[i].CPagerWin[2] = XCreateWindow(dpy, Desks[i].w, -1000, -1000, 3, h, 0,
			     CopyFromParent, InputOutput, CopyFromParent,
						 valuemask, &attributes);

		Desks[i].CPagerWin[3] = XCreateWindow(dpy, Desks[i].w, -1000, -1000, 3, h, 0,
			     CopyFromParent, InputOutput, CopyFromParent,
						 valuemask, &attributes);

		for (l = 0; l < 4; l++)
			XMapRaised(dpy, Desks[i].CPagerWin[l]);
		XMapRaised(dpy, Desks[i].w);
		XMapRaised(dpy, Desks[i].title_w);

		if (Desks[i].pixmap != 0) {
			XSetWindowBackgroundPixmap(dpy, Desks[i].w, Desks[i].pixmap);
			XClearWindow(dpy, Desks[i].w);
		}
	}
	XMapRaised(dpy, Scr.Pager_w);

	gcm = GCForeground | GCBackground | GCFont;
	gcv.foreground = fore_pix;
	gcv.background = back_pix;

	gcv.font = font->fid;
	NormalGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);

	gcv.foreground = hi_pix;
	if (Scr.d_depth < 2) {
		gcv.foreground = fore_pix;
		gcv.background = back_pix;
	}
	HiliteGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);

	if ((Scr.d_depth < 2) || (fore_pix == hi_pix))
		gcv.foreground = back_pix;
	else
		gcv.foreground = fore_pix;
	rvGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);

	if (windowFont != NULL) {
		/* Create GC's for doing window labels */
		gcv.foreground = focus_fore_pix;
		gcv.background = focus_pix;
		gcv.font = windowFont->fid;
		StdGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);

		gcv.foreground = focus_fore_pix;
		gcv.background = focus_pix;
		FocusGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);
	}
}



/****************************************************************************
 * 
 * Loads a single color
 *
 ****************************************************************************/
Pixel GetColor(char *name)
{
	XColor color;
	XWindowAttributes attributes;

	XGetWindowAttributes(dpy, Scr.Root, &attributes);
	color.pixel = 0;
	if (!XParseColor(dpy, attributes.colormap, name, &color)) {
		nocolor("parse", name);
	} else if (!XAllocColor(dpy, attributes.colormap, &color)) {
		nocolor("alloc", name);
	}
	return color.pixel;
}


void nocolor(char *a, char *b)
{
	fprintf(stderr, "%s: can't %s %s\n", MyName, a, b);
}

/****************************************************************************
 *
 * Decide what to do about received X events
 *
 ****************************************************************************/
void DispatchEvent(XEvent * Event)
{
	int i, x, y;
	Window JunkRoot, JunkChild;
	int JunkX, JunkY;
	unsigned JunkMask;

	switch (Event->xany.type) {
	case ConfigureNotify:
		ReConfigure();
		break;
	case Expose:
		HandleExpose(Event);
		break;
	case ButtonRelease:
		if ((Event->xbutton.button == 1) ||
		    (Event->xbutton.button == 2)) {
			for (i = 0; i < ndesks; i++) {
				if (Event->xany.window == Desks[i].w)
					SwitchToDeskAndPage(i, Event);
				if (Event->xany.window == Desks[i].title_w)
					SwitchToDesk(i);
			}
			if (Event->xany.window == icon_win) {
				IconSwitchPage(Event);
			}
		} else if (Event->xbutton.button == 3) {
			for (i = 0; i < ndesks; i++) {
				if (Event->xany.window == Desks[i].w) {
					XQueryPointer(dpy, Desks[i].w, &JunkRoot, &JunkChild,
						      &JunkX, &JunkY, &x, &y, &JunkMask);
					Scroll(i, x, y);
				}
			}
			if (Event->xany.window == icon_win) {
				XQueryPointer(dpy, icon_win, &JunkRoot, &JunkChild,
				      &JunkX, &JunkY, &x, &y, &JunkMask);
				IconScroll(x, y);
			}
		}
		break;
	case ButtonPress:
		if (((Event->xbutton.button == 2) ||
		     ((Event->xbutton.button == 3) &&
		      (Event->xbutton.state & Mod1Mask))) &&
		    (Event->xbutton.subwindow != None)) {
			MoveWindow(Event);
		} else if (Event->xbutton.button == 3) {
			for (i = 0; i < ndesks; i++) {
				if (Event->xany.window == Desks[i].w) {
					XQueryPointer(dpy, Desks[i].w, &JunkRoot, &JunkChild,
						      &JunkX, &JunkY, &x, &y, &JunkMask);
					Scroll(i, x, y);
				}
			}
			if (Event->xany.window == icon_win) {
				XQueryPointer(dpy, icon_win, &JunkRoot, &JunkChild,
				      &JunkX, &JunkY, &x, &y, &JunkMask);
				IconScroll(x, y);
			}
		}
		break;
	case MotionNotify:
		while (XCheckMaskEvent(dpy, PointerMotionMask | ButtonMotionMask, Event));

		if (Event->xmotion.state == Button3MotionMask) {
			for (i = 0; i < ndesks; i++) {
				if (Event->xany.window == Desks[i].w) {
					XQueryPointer(dpy, Desks[i].w, &JunkRoot, &JunkChild,
						      &JunkX, &JunkY, &x, &y, &JunkMask);
					Scroll(i, x, y);
				}
			}
			if (Event->xany.window == icon_win) {
				XQueryPointer(dpy, icon_win, &JunkRoot, &JunkChild,
				      &JunkX, &JunkY, &x, &y, &JunkMask);
				IconScroll(x, y);
			}
		}
		break;

	case ClientMessage:
		if ((Event->xclient.format == 32) &&
		    (Event->xclient.data.l[0] == wm_del_win)) {
			exit(0);
		}
		break;
	}
}

void HandleExpose(XEvent * Event)
{
	int i;
	PagerWindow *t;

	for (i = 0; i < ndesks; i++) {
		if ((Event->xany.window == Desks[i].w)
		    || (Event->xany.window == Desks[i].title_w))
			DrawGrid(i, 0);
	}
	if (Event->xany.window == icon_win)
		DrawIconGrid(0);

	t = Start;
	while (t != NULL) {
		if (t->PagerView == Event->xany.window) {
			LabelWindow(t);
		} else if (t->IconView == Event->xany.window) {
			LabelIconWindow(t);
		}
		t = t->next;
	}
}


/****************************************************************************
 *
 * Respond to a change in window geometry.
 *
 ****************************************************************************/
void ReConfigure(void)
{
	Window root;
	unsigned border_width, depth;
	int n, m, w, h, n1, m1, x, y, i, j, k, l;


	XGetGeometry(dpy, Scr.Pager_w, &root, &x, &y,
		     (unsigned *) &window_w, (unsigned *) &window_h,
		     &border_width, &depth);

	n1 = Scr.Vx / Scr.MyDisplayWidth;
	m1 = Scr.Vy / Scr.MyDisplayHeight;
	n = (Scr.VxMax) / Scr.MyDisplayWidth;
	m = (Scr.VyMax) / Scr.MyDisplayHeight;
	desk_w = (window_w - Columns + 1) / Columns;
	desk_h = (window_h - Rows * label_h - Rows + 2) / Rows;
	w = (desk_w - n) / (n + 1);
	h = (desk_h - m) / (m + 1);

	x = (desk_w - n) * Scr.Vx / (Scr.VxMax + Scr.MyDisplayWidth) + n1;
	y = (desk_h - m) * Scr.Vy / (Scr.VyMax + Scr.MyDisplayHeight) + m1;

	scr_w = w;
	scr_h = h;
	for (k = 0; k < Rows; k++) {
		for (j = 0; j < Columns; j++) {
			i = k * Columns + j;

			if (i < ndesks) {
				XMoveResizeWindow(dpy, Desks[i].title_w,
						  (desk_w + 1) * j - 1, (desk_h + label_h + 1) * k - 1,
						  desk_w, window_h);
				XMoveResizeWindow(dpy, Desks[i].w, -1, label_h - 1,
						  desk_w, desk_h);
				if (i == Scr.CurrentDesk - desk1) {
					XMoveResizeWindow(dpy, Desks[i].CPagerWin[0], x - 3, y - 3, w + 6, 3);
					XMoveResizeWindow(dpy, Desks[i].CPagerWin[1], x - 3, y + h, w + 6, 3);
					XMoveResizeWindow(dpy, Desks[i].CPagerWin[2], x - 3, y, 3, h);
					XMoveResizeWindow(dpy, Desks[i].CPagerWin[3], x + w, y, 3, h);
				} else {
					XMoveResizeWindow(dpy, Desks[i].CPagerWin[0], -1000, -1000, w + 6, 3);
					XMoveResizeWindow(dpy, Desks[i].CPagerWin[1], -1000, -1000, w + 6, 3);
					XMoveResizeWindow(dpy, Desks[i].CPagerWin[2], -1000, -1000, 3, h);
					XMoveResizeWindow(dpy, Desks[i].CPagerWin[3], -1000, -1000, 3, h);
				}
				XClearArea(dpy, Desks[i].w, 0, 0, desk_w,
					   desk_h, True);
				if (uselabel)
					XClearArea(dpy, Desks[i].title_w, 0, 0, desk_w,
						   label_h, True);
			}
		}
	}
	/* reconfigure all the subordinate windows */
	ReConfigureAll();
}

void MovePage(void)
{
	int n1, m1, x, y, n, m, i, l, w, h;
	XTextProperty name;
	char str[100], *sptr;
	static int icon_desk_shown = -1000;

	Wait = 0;
	n1 = Scr.Vx / Scr.MyDisplayWidth;
	m1 = Scr.Vy / Scr.MyDisplayHeight;
	n = (Scr.VxMax) / Scr.MyDisplayWidth;
	m = (Scr.VyMax) / Scr.MyDisplayHeight;

	x = (desk_w - n) * Scr.Vx / (Scr.VxMax + Scr.MyDisplayWidth) + n1;
	y = (desk_h - m) * Scr.Vy / (Scr.VyMax + Scr.MyDisplayHeight) + m1;

	for (i = 0; i < ndesks; i++) {
		if (i == Scr.CurrentDesk - desk1) {
			w = (window_w - n) / (n + 1);
			h = (window_h - label_h - m) / (m + 1);
			XMoveWindow(dpy, Desks[i].CPagerWin[0], x - 3, y - 3);
			XMoveWindow(dpy, Desks[i].CPagerWin[1], x - 3, y + scr_h);
			XMoveWindow(dpy, Desks[i].CPagerWin[2], x - 3, y);
			XMoveWindow(dpy, Desks[i].CPagerWin[3], x + scr_w, y);

			/*XMoveWindow(dpy, Desks[i].CPagerWin, x,y); */
			for (l = 0; l < 4; l++)
				XLowerWindow(dpy, Desks[i].CPagerWin[l]);
		} else
			/*XMoveWindow(dpy, Desks[i].CPagerWin, -1000,-1000); */
			for (l = 0; l < 4; l++)
				XMoveWindow(dpy, Desks[i].CPagerWin[l], -1000, -1000);

	}
	DrawIconGrid(1);

	ReConfigureIcons();

	if (Scr.CurrentDesk != icon_desk_shown) {
		icon_desk_shown = Scr.CurrentDesk;

		if ((Scr.CurrentDesk >= desk1) && (Scr.CurrentDesk <= desk2))
			sptr = Desks[Scr.CurrentDesk - desk1].label;
		else {
			sprintf(str, "Desk %d", Scr.CurrentDesk);
			sptr = &str[0];
		}
		if (XStringListToTextProperty(&sptr, 1, &name) == 0) {
			fprintf(stderr, "%s: cannot allocate window name", MyName);
			return;
		}
		XSetWMIconName(dpy, Scr.Pager_w, &name);
	}
}

void ReConfigureAll(void)
{
	PagerWindow *t;

	t = Start;
	while (t != NULL) {
		MoveResizePagerView(t);
		t = t->next;
	}
}

void ReConfigureIcons(void)
{
	PagerWindow *t;
	int x, y, w, h, n, m, n1, m1;

	n = (Scr.VxMax) / Scr.MyDisplayWidth;
	m = (Scr.VyMax) / Scr.MyDisplayHeight;

	t = Start;
	while (t != NULL) {
		n1 = (Scr.Vx + t->x) / Scr.MyDisplayWidth;
		m1 = (Scr.Vy + t->y) / Scr.MyDisplayHeight;
		x = (Scr.Vx + t->x) * (icon_w - n) / (Scr.VxMax + Scr.MyDisplayWidth) + n1;
		y = (Scr.Vy + t->y) * (icon_h - m) / (Scr.VyMax + Scr.MyDisplayHeight) + m1;
		w = (Scr.Vx + t->x + t->width + 2) * (icon_w - n) /
		    (Scr.VxMax + Scr.MyDisplayWidth) - 2 - x + n1;
		h = (Scr.Vy + t->y + t->height + 2) * (icon_h - m) /
		    (Scr.VyMax + Scr.MyDisplayHeight) - 2 - y + m1;

		if (w < 1)
			w = 1;
		if (h < 1)
			h = 1;

		if (Scr.CurrentDesk == t->desk)
			XMoveResizeWindow(dpy, t->IconView, x, y, w, h);
		else
			XMoveResizeWindow(dpy, t->IconView, -1000, -1000, w, h);
		t = t->next;
	}
}


/********
 set RootWindowXPM
 ********/

void SetRootPixmap(long Desk)
{
	if (Desk == 10000)
		return;
	/*Desk=(Scr.CurrentDesk - desk1); */
	XSetWindowBackgroundPixmap(dpy, Scr.Root, Desks[Desk].pixmap);
	XClearWindow(dpy, Scr.Root);
}

/****************************************************************************
 *
 * Draw Background for Desks
 *
 ****************************************************************************/

void DrawBack(int Desk, char *xpmFile)
{
	XWindowAttributes win_attr;
	XpmAttributes xpm_attributes;
	Pixmap shapeMask;
	int val;
	char *realfilename;

/* Save up default bg filename for later use */
	strcpy (defaultbgfile[Desk], xpmFile);

	if (((Desks[Desk].pixmap == 0) || (defaultbgfile[Desk] != NULL)) && (xpmFile != NULL)) {
		XGetWindowAttributes(dpy, Scr.Root, &win_attr);
		xpm_attributes.colormap = win_attr.colormap;
		xpm_attributes.valuemask = XpmSize | XpmReturnPixels | XpmColormap | XpmCloseness;
		xpm_attributes.closeness = 40000;

/* home ? */
		realfilename = PutHome(xpmFile);

		if ((val = XpmReadFileToPixmap(dpy, Scr.Root, realfilename, &Desks[Desk].pixmap, &shapeMask, &xpm_attributes)) != XpmSuccess) {
			free(realfilename);

			if (val == XpmOpenFailed)
				fprintf(stderr, "Couldn't open pixmap file\n");
			else if (val == XpmColorFailed)
				fprintf(stderr, "Couldn't allocate required colors\n");
			else if (val == XpmFileInvalid)
				fprintf(stderr, "Invalid Xpm File\n");
			else if (val == XpmColorError)
				fprintf(stderr, "Invalid Color specified in Xpm file\n");
			else if (val == XpmNoMemory)
				fprintf(stderr, "Insufficient Memory\n");
			fprintf(stderr, "No success reading XPM\n");
			exit(1);
		}
		free(realfilename);

	}
/*   XSetWindowBackgroundPixmap(dpy,Desks[Desk].w,Desks[Desk].pixmap);
   XClearWindow(dpy,Desks[Desk].w); */
}

/****************************************************************************
 *
 * Draw grid lines for desk #i
 *
 ****************************************************************************/
void DrawGrid(int i, int erase)
{
	int y, y1, y2, x, x1, x2, d, hor_off, w;
	int MaxW, MaxH;
	char str[15], *ptr;

	if ((i < 0) || (i >= ndesks))
		return;

	MaxW = (Scr.VxMax + Scr.MyDisplayWidth);
	MaxH = Scr.VyMax + Scr.MyDisplayHeight;

	x = Scr.MyDisplayWidth;
	y1 = 0;
	y2 = desk_h;

	while (x < MaxW) {
		x1 = x * desk_w / MaxW;
		XDrawLine(dpy, Desks[i].w, NormalGC, x1, y1, x1, y2);
		x += Scr.MyDisplayWidth;
	}

	y = Scr.MyDisplayHeight;
	x1 = 0;
	x2 = desk_w;
	while (y < MaxH) {
		y1 = y * (desk_h) / MaxH;
		XDrawLine(dpy, Desks[i].w, NormalGC, x1, y1, x2, y1);
		y += Scr.MyDisplayHeight;
	}
	if ((Scr.CurrentDesk - desk1) == i) {
		if (uselabel)
			XFillRectangle(dpy, Desks[i].title_w, HiliteGC,
				       0, 0, desk_w, label_h - 1);
	} else {
		if (uselabel && erase)
			XClearArea(dpy, Desks[i].title_w,
				   0, 0, desk_w, label_h - 1, False);
	}
	d = desk1 + i;
	ptr = Desks[i].label;
	w = XTextWidth(font, ptr, strlen(ptr));
	if (w > desk_w) {
		sprintf(str, "%d", d);
		ptr = str;
		w = XTextWidth(font, ptr, strlen(ptr));
	}
	if ((w <= desk_w) && (uselabel)) {
		hor_off = (desk_w - w) / 2;
		if (TitleAlign > 0)
			XDrawString(dpy, Desks[i].title_w,
				    (i == (Scr.CurrentDesk - desk1)) ? rvGC : NormalGC,
			 TitleAlign, font->ascent + 1, ptr, strlen(ptr));
		else if (TitleAlign == 0)
			XDrawString(dpy, Desks[i].title_w,
				    (i == (Scr.CurrentDesk - desk1)) ? rvGC : NormalGC,
			    hor_off, font->ascent + 1, ptr, strlen(ptr));
		else
			XDrawString(dpy, Desks[i].title_w,
				    (i == (Scr.CurrentDesk - desk1)) ? rvGC : NormalGC,
				    desk_w - w + TitleAlign, font->ascent + 1, ptr, strlen(ptr));
	}
}


void DrawIconGrid(int erase)
{
	int y, y1, y2, x, x1, x2, w, h, n, m, n1, m1;
	int MaxW, MaxH;

	MaxW = (Scr.VxMax + Scr.MyDisplayWidth);
	MaxH = Scr.VyMax + Scr.MyDisplayHeight;

	if (erase)
		XClearWindow(dpy, icon_win);
	x = Scr.MyDisplayWidth;
	y1 = 0;
	y2 = icon_h;
	while (x < MaxW) {
		x1 = x * icon_w / MaxW;
		XDrawLine(dpy, icon_win, NormalGC, x1, y1, x1, y2);
		x += Scr.MyDisplayWidth;
	}

	y = Scr.MyDisplayHeight;
	x1 = 0;
	x2 = icon_w;
	while (y < MaxH) {
		y1 = y * (icon_h) / MaxH;
		XDrawLine(dpy, icon_win, NormalGC, x1, y1, x2, y1);
		y += Scr.MyDisplayHeight;
	}
	n1 = Scr.Vx / Scr.MyDisplayWidth;
	m1 = Scr.Vy / Scr.MyDisplayHeight;
	n = (Scr.VxMax) / Scr.MyDisplayWidth;
	m = (Scr.VyMax) / Scr.MyDisplayHeight;
	w = (icon_w - n) / (n + 1);
	h = (icon_h - m) / (m + 1);

	x = (icon_w - n) * Scr.Vx / (Scr.VxMax + Scr.MyDisplayWidth) + n1;
	y = (icon_h - m) * Scr.Vy / (Scr.VyMax + Scr.MyDisplayHeight) + m1;

	XFillRectangle(dpy, icon_win, HiliteGC,
		       x, y, w, h);

}


void SwitchToDesk(int Desk)
{
	char command[256];

	sprintf(command, "Desk 0 %d\n", Desk + desk1);

	SendInfo(fd, command, 0);
}


void SwitchToDeskAndPage(int Desk, XEvent * Event)
{
	char command[256];

	SendInfo(fd, "Desk 0 10000\n", 0);
#ifndef NON_VIRTUAL
	sprintf(command, "GotoPage %d %d\n",
		Event->xbutton.x * (Scr.VxMax + Scr.MyDisplayWidth) /
		(desk_w * Scr.MyDisplayWidth),
		Event->xbutton.y * (Scr.VyMax + Scr.MyDisplayHeight) /
		(desk_h * Scr.MyDisplayHeight));
	SendInfo(fd, command, 0);

        if (Scr.CurrentDesk == Desk + desk1) /* just changing page */
		sprintf(command, "Desk 0 %d\n", Desk + desk1);
	else /* really changing desk */
        	sprintf(command, "Desk 10000 %d\n", Desk + desk1);
	SendInfo(fd, command, 0);

#endif
	Wait = 1;

}

void IconSwitchPage(XEvent * Event)
{
	char command[256];

#ifndef NON_VIRTUAL
	sprintf(command, "GotoPage %d %d\n",
		Event->xbutton.x * (Scr.VxMax + Scr.MyDisplayWidth) /
		(icon_w * Scr.MyDisplayWidth),
		Event->xbutton.y * (Scr.VyMax + Scr.MyDisplayHeight) /
		(icon_h * Scr.MyDisplayHeight));
	SendInfo(fd, command, 0);
#endif
	Wait = 1;
}


void AddNewWindow(PagerWindow * t)
{
	unsigned long valuemask;
	XSetWindowAttributes attributes;
	int i, x, y, w, h, n, m, n1, m1;

	i = t->desk - desk1;
	n = (Scr.VxMax) / Scr.MyDisplayWidth;
	m = (Scr.VyMax) / Scr.MyDisplayHeight;
	n1 = (Scr.Vx + t->x) / Scr.MyDisplayWidth;
	m1 = (Scr.Vy + t->y) / Scr.MyDisplayHeight;
	x = (Scr.Vx + t->x) * (desk_w - n) / (Scr.VxMax + Scr.MyDisplayWidth) + n1;
	y = (Scr.Vy + t->y) * (desk_h - m) / (Scr.VyMax + Scr.MyDisplayHeight) + m1;
	w = (Scr.Vx + t->x + t->width + 2) * (desk_w - n) /
	    (Scr.VxMax + Scr.MyDisplayWidth) - 2 - x + n1;
	h = (Scr.Vy + t->y + t->height + 2) * (desk_h - m) /
	    (Scr.VyMax + Scr.MyDisplayHeight) - 2 - y + m1;
	if (w < 1)
		w = 1;
	if (h < 1)
		h = 1;

	valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
	attributes.background_pixel = t->back;
	attributes.border_pixel = fore_pix;
	attributes.event_mask = (ExposureMask);

	if ((i >= 0) && (i < ndesks)) {
		t->PagerView = XCreateWindow(dpy, Desks[i].w, x, y, w, h, 1,
					     CopyFromParent,
					     InputOutput, CopyFromParent,
					     valuemask, &attributes);

		XMapRaised(dpy, t->PagerView);
	} else
		t->PagerView = None;


	x = (Scr.Vx + t->x) * (icon_w - n) / (Scr.VxMax + Scr.MyDisplayWidth) + n1;
	y = (Scr.Vy + t->y) * (icon_h - m) / (Scr.VyMax + Scr.MyDisplayHeight) + m1;
	w = (Scr.Vx + t->x + t->width + 2) * (icon_w - n) /
	    (Scr.VxMax + Scr.MyDisplayWidth) - 2 - x + n1;
	h = (Scr.Vy + t->y + t->height + 2) * (icon_h - m) /
	    (Scr.VyMax + Scr.MyDisplayHeight) - 2 - y + m1;
	if (w < 1)
		w = 1;
	if (h < 1)
		h = 1;

	if (Scr.CurrentDesk == t->desk) {
		t->IconView = XCreateWindow(dpy, icon_win, x, y, w, h, 1,
					    CopyFromParent,
					    InputOutput, CopyFromParent,
					    valuemask, &attributes);
		XGrabButton(dpy, 2, AnyModifier, t->IconView,
			    True, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
			    GrabModeAsync, GrabModeAsync, None,
			    None);
		XMapRaised(dpy, t->IconView);
	} else {
		t->IconView = XCreateWindow(dpy, icon_win, -1000, -1000, w, h, 1,
					    CopyFromParent,
					    InputOutput, CopyFromParent,
					    valuemask, &attributes);
		XMapRaised(dpy, t->IconView);
	}
	Hilight(t, OFF);
}



void ChangeDeskForWindow(PagerWindow * t, long newdesk)
{
	int i, x, y, w, h, n, m, n1, m1;

	i = newdesk - desk1;

	if (t->PagerView == None) {
		t->desk = newdesk;
		XDestroyWindow(dpy, t->IconView);
		AddNewWindow(t);
		return;
	}
	n = (Scr.VxMax) / Scr.MyDisplayWidth;
	m = (Scr.VyMax) / Scr.MyDisplayHeight;
	n1 = (Scr.Vx + t->x) / Scr.MyDisplayWidth;
	m1 = (Scr.Vy + t->y) / Scr.MyDisplayHeight;
	x = (Scr.Vx + t->x) * (desk_w - n) / (Scr.VxMax + Scr.MyDisplayWidth) + n1;
	y = (Scr.Vy + t->y) * (desk_h - m) / (Scr.VyMax + Scr.MyDisplayHeight) + m1;
	w = (Scr.Vx + t->x + t->width + 2) * (desk_w - n) / (Scr.VxMax + Scr.MyDisplayWidth) - 2 - x + n1;
	h = (Scr.Vy + t->y + t->height + 2) * (desk_h - m) / (Scr.VyMax + Scr.MyDisplayHeight) - 2 - y + m1;
	if (w < 1)
		w = 1;
	if (h < 1)
		h = 1;
	if ((i >= 0) && (i < ndesks)) {
		XReparentWindow(dpy, t->PagerView, Desks[i].w, x, y);
		XResizeWindow(dpy, t->PagerView, w, h);
	} else {
		XDestroyWindow(dpy, t->PagerView);
		t->PagerView = None;
	}
	t->desk = i + desk1;

	x = (Scr.Vx + t->x) * (icon_w - n) / (Scr.VxMax + Scr.MyDisplayWidth) + n1;
	y = (Scr.Vy + t->y) * (icon_h - m) / (Scr.VyMax + Scr.MyDisplayHeight) + m1;
	w = (Scr.Vx + t->x + t->width + 2) * (icon_w - n) / (Scr.VxMax + Scr.MyDisplayWidth) - 2 - x + n1;
	h = (Scr.Vy + t->y + t->height + 2) * (icon_h - m) / (Scr.VyMax + Scr.MyDisplayHeight) - 2 - y + m1;
	if (w < 1)
		w = 1;
	if (h < 1)
		h = 1;
	if (Scr.CurrentDesk == t->desk)
		XMoveResizeWindow(dpy, t->IconView, x, y, w, h);
	else
		XMoveResizeWindow(dpy, t->IconView, -1000, -1000, w, h);
}

void MoveResizePagerView(PagerWindow * t)
{
	int x, y, w, h, n, m, n1, m1;

	n = (Scr.VxMax) / Scr.MyDisplayWidth;
	m = (Scr.VyMax) / Scr.MyDisplayHeight;
	n1 = (Scr.Vx + t->x) / Scr.MyDisplayWidth;
	m1 = (Scr.Vy + t->y) / Scr.MyDisplayHeight;
	x = (Scr.Vx + t->x) * (desk_w - n) / (Scr.VxMax + Scr.MyDisplayWidth) + n1;
	y = (Scr.Vy + t->y) * (desk_h - m) / (Scr.VyMax + Scr.MyDisplayHeight) + m1;
	w = (Scr.Vx + t->x + t->width + 2) * (desk_w - n) /
	    (Scr.VxMax + Scr.MyDisplayWidth) - 2 - x + n1;
	h = (Scr.Vy + t->y + t->height + 2) * (desk_h - m) /
	    (Scr.VyMax + Scr.MyDisplayHeight) - 2 - y + m1;

	if (w < 1)
		w = 1;
	if (h < 1)
		h = 1;
	if (t->PagerView != None)
		XMoveResizeWindow(dpy, t->PagerView, x, y, w, h);
	else if ((t->desk >= desk1) && (t->desk <= desk2)) {
		XDestroyWindow(dpy, t->IconView);
		AddNewWindow(t);
		return;
	}
	x = (Scr.Vx + t->x) * (icon_w - n) / (Scr.VxMax + Scr.MyDisplayWidth) + n1;
	y = (Scr.Vy + t->y) * (icon_h - m) / (Scr.VyMax + Scr.MyDisplayHeight) + m1;
	w = (Scr.Vx + t->x + t->width + 2) * (icon_w - n) /
	    (Scr.VxMax + Scr.MyDisplayWidth) - 2 - x + n1;
	h = (Scr.Vy + t->y + t->height + 2) * (icon_h - m) /
	    (Scr.VyMax + Scr.MyDisplayHeight) - 2 - y + m1;

	if (w < 1)
		w = 1;
	if (h < 1)
		h = 1;
	if (Scr.CurrentDesk == t->desk)
		XMoveResizeWindow(dpy, t->IconView, x, y, w, h);
	else
		XMoveResizeWindow(dpy, t->IconView, -1000, -1000, w, h);
}


void MoveStickyWindows(void)
{
	PagerWindow *t;

	t = Start;
	while (t != NULL) {
		if (((t->flags & ICONIFIED) && (StickyIcons)) ||
		    (t->flags & STICKY)) {
			if (t->desk != Scr.CurrentDesk) {
				ChangeDeskForWindow(t, Scr.CurrentDesk);
			} else {
				MoveResizePagerView(t);

			}
		}
		t = t->next;
	}
}

void Hilight(PagerWindow * t, int on)
{

	if (!t)
		return;

	if (Scr.d_depth < 2) {
		if (on) {
			if (t->PagerView != None)
				XSetWindowBackgroundPixmap(dpy, t->PagerView, Scr.gray_pixmap);
			XSetWindowBackgroundPixmap(dpy, t->IconView, Scr.gray_pixmap);
		} else {
			if (t->flags & STICKY) {
				if (t->PagerView != None)
					XSetWindowBackgroundPixmap(dpy, t->PagerView,
						 Scr.sticky_gray_pixmap);
				XSetWindowBackgroundPixmap(dpy, t->IconView,
						 Scr.sticky_gray_pixmap);
			} else {
				if (t->PagerView != None)
					XSetWindowBackgroundPixmap(dpy, t->PagerView,
						  Scr.light_gray_pixmap);
				XSetWindowBackgroundPixmap(dpy, t->IconView,
						  Scr.light_gray_pixmap);
			}
		}
	} else {
		if (on) {
			if (t->PagerView != None)
				XSetWindowBackground(dpy, t->PagerView, focus_pix);
			XSetWindowBackground(dpy, t->IconView, focus_pix);
		} else {
			if (t->PagerView != None)
				XSetWindowBackground(dpy, t->PagerView, t->back);
			XSetWindowBackground(dpy, t->IconView, t->back);
		}
	}
	if (t->PagerView != None)
		XClearWindow(dpy, t->PagerView);
	XClearWindow(dpy, t->IconView);
	LabelWindow(t);
	LabelIconWindow(t);
}

void Scroll(int Desk, int x, int y)
{
#ifndef NON_VIRTUAL
	char command[256];
	int sx, sy;
	if (Wait == 0) {
		if (Desk != Scr.CurrentDesk) {
			return;
		}
		if (x < 0)
			x = 0;
		if (y < 0)
			y = 0;

		if (x > desk_w)
			x = desk_w;
		if (y > desk_h)
			y = desk_h;

		sx = (100 * (x * (Scr.VxMax + Scr.MyDisplayWidth) / desk_w - Scr.Vx)) / Scr.MyDisplayWidth;
		sy = (100 * (y * (Scr.VyMax + Scr.MyDisplayHeight) /
			     desk_h - Scr.Vy)) / Scr.MyDisplayHeight;
		if (sx > 100)
			sx = 100;
		if (sx < -100)
			sx = -100;
		if (sy < -100)
			sy = -100;
		if (sy > 100)
			sy = 100;

		sprintf(command, "Scroll %d %d\n", sx, sy);
		SendInfo(fd, command, 0);
		Wait = 1;
	}
#endif
}


void IconScroll(int x, int y)
{
#ifndef NON_VIRTUAL
	char command[256];
	int sx, sy;
	if (Wait == 0) {
		if (x < 0)
			x = 0;
		if (y < 0)
			y = 0;

		if (x > icon_w)
			x = icon_w;
		if (y > icon_h)
			y = icon_h;

		sx = (100 * (x * (Scr.VxMax + Scr.MyDisplayWidth) / icon_w - Scr.Vx)) / Scr.MyDisplayWidth;
		sy = (100 * (y * (Scr.VyMax + Scr.MyDisplayHeight) /
			     icon_h - Scr.Vy)) / Scr.MyDisplayHeight;
		if (sx > 100)
			sx = 100;
		if (sx < -100)
			sx = -100;
		if (sy < -100)
			sy = -100;
		if (sy > 100)
			sy = 100;

		sprintf(command, "Scroll %d %d\n", sx, sy);
		SendInfo(fd, command, 0);
		Wait = 1;
	}
#endif
}


void MoveWindow(XEvent * Event)
{
	char command[100];
	int x1, y1, finished = 0, wx, wy, n, x, y, xi = 0, yi = 0, wx1,
	 wy1, x2, y2;
	Window dumwin;
	PagerWindow *t;
	int m, n1, m1;
	int NewDesk, KeepMoving = 0;
	int moved = 0;
	int row, column;

	t = Start;
	while ((t != NULL) && (t->PagerView != Event->xbutton.subwindow))
		t = t->next;

	if (t == NULL) {
		t = Start;
		while ((t != NULL) && (t->IconView != Event->xbutton.subwindow))
			t = t->next;
		if (t != NULL) {
			IconMoveWindow(Event, t);
			return;
		}
	}
	if (t == NULL)
		return;

	NewDesk = t->desk - desk1;
	if ((NewDesk < 0) || (NewDesk >= ndesks))
		return;

	n = (Scr.VxMax) / Scr.MyDisplayWidth;
	m = (Scr.VyMax) / Scr.MyDisplayHeight;
	n1 = (Scr.Vx + t->x) / Scr.MyDisplayWidth;
	m1 = (Scr.Vy + t->y) / Scr.MyDisplayHeight;
	wx = (Scr.Vx + t->x) * (desk_w - n) / (Scr.VxMax + Scr.MyDisplayWidth) + n1;
	wy = (Scr.Vy + t->y) * (desk_h - m) / (Scr.VyMax + Scr.MyDisplayHeight) + m1;
	wx1 = wx + (desk_w + 1) * (NewDesk % Columns);
	wy1 = wy + label_h + (desk_h + label_h + 1) * (NewDesk / Columns);

	XReparentWindow(dpy, t->PagerView, Scr.Pager_w, wx1, wy1);
	XRaiseWindow(dpy, t->PagerView);

	XTranslateCoordinates(dpy, Event->xany.window, t->PagerView,
		  Event->xbutton.x, Event->xbutton.y, &x1, &y1, &dumwin);
	xi = x1;
	yi = y1;
	while (!finished) {
		XMaskEvent(dpy, ButtonReleaseMask | ButtonMotionMask | ExposureMask, Event);

		if (Event->type == MotionNotify) {
			XTranslateCoordinates(dpy, Event->xany.window, Scr.Pager_w,
			      Event->xmotion.x, Event->xmotion.y, &x, &y,
					      &dumwin);
			if (moved == 0) {
				xi = x;
				yi = y;
				moved = 1;
			}
			if ((x < -5) || (y < -5) || (x > window_w + 5) || (y > window_h + 5)) {
				KeepMoving = 1;
				finished = 1;
			}
			XMoveWindow(dpy, t->PagerView, x - (x1),
				    y - (y1));
		} else if (Event->type == ButtonRelease) {
			XTranslateCoordinates(dpy, Event->xany.window, Scr.Pager_w,
			      Event->xbutton.x, Event->xbutton.y, &x, &y,
					      &dumwin);
			XMoveWindow(dpy, t->PagerView, x - (x1),
				    y - (y1));
			finished = 1;
		} else if (Event->type == Expose) {
			HandleExpose(Event);
		}
	}

	if (moved) {
		if ((x - xi < 3) && (y - yi < 3) &&
		    (x - xi > -3) && (y - yi > -3))
			moved = 0;
	}
	if (KeepMoving) {
		NewDesk = Scr.CurrentDesk;
		if (NewDesk != t->desk) {
			XMoveWindow(dpy, t->w, Scr.MyDisplayWidth + Scr.VxMax,
				    Scr.MyDisplayHeight + Scr.VyMax);
			XSync(dpy, 0);
			sprintf(command, "WindowsDesk %d", NewDesk);
			SendInfo(fd, command, t->w);
			t->desk = NewDesk;
		}
		if ((NewDesk >= desk1) && (NewDesk <= desk2))
			XReparentWindow(dpy, t->PagerView, Desks[NewDesk - desk1].w, 0, 0);
		else {
			XDestroyWindow(dpy, t->PagerView);
			t->PagerView = None;
		}
		XTranslateCoordinates(dpy, Scr.Pager_w, Scr.Root,
				      x, y, &x1, &y1, &dumwin);
		if (t->flags & ICONIFIED) {
			XUngrabPointer(dpy, CurrentTime);
			XSync(dpy, 0);
			SendInfo(fd, "Move", t->icon_w);
		} else {
			XUngrabPointer(dpy, CurrentTime);
			XSync(dpy, 0);
			SendInfo(fd, "Move", t->w);
		}
		return;
	} else {
		column = (x / (desk_w + 1));
		row = (y / (desk_h + label_h + 1));
		NewDesk = column + (row) * Columns;
		if ((NewDesk < 0) || (NewDesk >= ndesks)) {
			NewDesk = Scr.CurrentDesk - desk1;
			x = xi;
			y = yi;
			moved = 0;
		}
		XTranslateCoordinates(dpy, Scr.Pager_w, Desks[NewDesk].w,
				      x - x1, y - y1, &x2, &y2, &dumwin);

		n1 = x2 * (Scr.VxMax + Scr.MyDisplayWidth) / (desk_w * Scr.MyDisplayWidth);
		m1 = y2 * (Scr.VyMax + Scr.MyDisplayHeight) / (desk_h * Scr.MyDisplayHeight);
		x = (x2 - n1) *
		    (Scr.VxMax + Scr.MyDisplayWidth) / (desk_w - n) - Scr.Vx;
		y = (y2 - m1) *
		    (Scr.VyMax + Scr.MyDisplayHeight) / (desk_h - m) - Scr.Vy;
		if (x + t->frame_width + Scr.Vx < 0)
			x = -Scr.Vx;
		if (y + t->frame_height + Scr.Vy < 0)
			y = -Scr.Vy;
		if (x + Scr.Vx > Scr.MyDisplayWidth + Scr.VxMax)
			x = Scr.MyDisplayWidth + Scr.VxMax - t->frame_width - Scr.Vx;
		if (y + Scr.Vy > Scr.MyDisplayHeight + Scr.VyMax)
			y = Scr.MyDisplayHeight + Scr.VyMax - t->frame_height - Scr.Vy;
		if (((t->flags & ICONIFIED) && (StickyIcons)) ||
		    (t->flags & STICKY)) {
			NewDesk = Scr.CurrentDesk - desk1;
			if (x > Scr.MyDisplayWidth - 16)
				x = Scr.MyDisplayWidth - 16;
			if (y > Scr.MyDisplayHeight - 16)
				y = Scr.MyDisplayHeight - 16;
			if (x + t->width < 16)
				x = 16 - t->width;
			if (y + t->height < 16)
				y = 16 - t->height;
		}
		if (NewDesk + desk1 != t->desk) {
			if (((t->flags & ICONIFIED) && (StickyIcons)) ||
			    (t->flags & STICKY)) {
				NewDesk = Scr.CurrentDesk - desk1;
				if (t->desk != Scr.CurrentDesk)
					ChangeDeskForWindow(t, Scr.CurrentDesk);
			} else {
				sprintf(command, "WindowsDesk %d", NewDesk + desk1);
				SendInfo(fd, command, t->w);
				t->desk = NewDesk + desk1;
			}
		}
		if ((NewDesk >= 0) && (NewDesk < ndesks)) {
			XReparentWindow(dpy, t->PagerView, Desks[NewDesk].w, x, y);
			if (moved) {
				if (t->flags & ICONIFIED)
					XMoveWindow(dpy, t->icon_w, x, y);
				else
					XMoveWindow(dpy, t->w, x + t->border_width,
						    y + t->title_height + t->border_width);
				XSync(dpy, 0);
			} else
				MoveResizePagerView(t);
			SendInfo(fd, "Raise", t->w);
		}
		if (Scr.CurrentDesk == t->desk) {
			if (t->flags & ICONIFIED)
				XSetInputFocus(dpy, t->icon_w, RevertToParent, Event->xbutton.time);
			else
				XSetInputFocus(dpy, t->w, RevertToParent, Event->xbutton.time);
		}
	}
}






/***********************************************************************
 *
 *  Procedure:
 *      ASErrorHandler - displays info on internal errors
 *
 ************************************************************************/
XErrorHandler ASErrorHandler(Display * dpy, XErrorEvent * event)
{
	return 0;
}


void LabelWindow(PagerWindow * t)
{
	XGCValues Globalgcv;
	unsigned long Globalgcm;
	GC tgc;

	if (windowFont == NULL) {
		return;
	}
	if (t->icon_name == NULL) {
		return;
	}
	if (t == FocusWin) {
		tgc = FocusGC;
	} else {
		tgc = StdGC;
		Globalgcv.foreground = t->text;
		Globalgcv.background = t->back;
		Globalgcm = GCForeground | GCBackground;
		XChangeGC(dpy, StdGC, Globalgcm, &Globalgcv);
	}
	if (t->PagerView != None) {
		XClearWindow(dpy, t->PagerView);
		XDrawImageString(dpy, t->PagerView, tgc, 2, windowFont->ascent + 2,
				 t->icon_name, strlen(t->icon_name));
	}
}


void LabelIconWindow(PagerWindow * t)
{
	XGCValues Globalgcv;
	unsigned long Globalgcm;
	GC tgc;

	if (windowFont == NULL) {
		return;
	}
	if (t->icon_name == NULL) {
		return;
	}
	if (t == FocusWin) {
		tgc = FocusGC;
	} else {
		tgc = StdGC;
		Globalgcv.foreground = t->text;
		Globalgcv.background = t->back;
		Globalgcm = GCForeground | GCBackground;
		XChangeGC(dpy, StdGC, Globalgcm, &Globalgcv);

	}
	XClearWindow(dpy, t->IconView);
	XDrawImageString(dpy, t->IconView, tgc, 2, windowFont->ascent + 2,
			 t->icon_name, strlen(t->icon_name));

}

void IconMoveWindow(XEvent * Event, PagerWindow * t)
{
	int x1, y1, finished = 0, wx, wy, n, x = 0, y = 0, xi = 0, yi = 0;
	Window dumwin;
	int m, n1, m1;
	int moved = 0;
	int KeepMoving = 0;

	if (t == NULL)
		return;

	n = (Scr.VxMax) / Scr.MyDisplayWidth;
	m = (Scr.VyMax) / Scr.MyDisplayHeight;
	n1 = (Scr.Vx + t->x) / Scr.MyDisplayWidth;
	m1 = (Scr.Vy + t->y) / Scr.MyDisplayHeight;
	wx = (Scr.Vx + t->x) * (icon_w - n) / (Scr.VxMax + Scr.MyDisplayWidth) + n1;
	wy = (Scr.Vy + t->y) * (icon_h - m) / (Scr.VyMax + Scr.MyDisplayHeight) + m1;

	XRaiseWindow(dpy, t->IconView);

	XTranslateCoordinates(dpy, Event->xany.window, t->IconView,
		  Event->xbutton.x, Event->xbutton.y, &x1, &y1, &dumwin);
	while (!finished) {
		XMaskEvent(dpy, ButtonReleaseMask | ButtonMotionMask | ExposureMask, Event);

		if (Event->type == MotionNotify) {
			x = Event->xbutton.x;
			y = Event->xbutton.y;
			if (moved == 0) {
				xi = x;
				yi = y;
				moved = 1;
			}
			XMoveWindow(dpy, t->IconView, x - (x1),
				    y - (y1));
			if ((x < -5) || (y < -5) || (x > icon_w + 5) || (y > icon_h + 5)) {
				finished = 1;
				KeepMoving = 1;
			}
		} else if (Event->type == ButtonRelease) {
			x = Event->xbutton.x;
			y = Event->xbutton.y;
			XMoveWindow(dpy, t->PagerView, x - (x1), y - (y1));
			finished = 1;
		} else if (Event->type == Expose) {
			HandleExpose(Event);
		}
	}

	if (moved) {
		if ((x - xi < 3) && (y - yi < 3) &&
		    (x - xi > -3) && (y - yi > -3))
			moved = 0;
	}
	if (KeepMoving) {
		XTranslateCoordinates(dpy, t->IconView, Scr.Root,
				      x, y, &x1, &y1, &dumwin);
		if (t->flags & ICONIFIED) {
			XUngrabPointer(dpy, CurrentTime);
			XSync(dpy, 0);
			SendInfo(fd, "Move", t->icon_w);
		} else {
			XUngrabPointer(dpy, CurrentTime);
			XSync(dpy, 0);
			SendInfo(fd, "Move", t->w);
		}
	} else {
		x = x - x1;
		y = y - y1;
		n1 = x * (Scr.VxMax + Scr.MyDisplayWidth) / (icon_w * Scr.MyDisplayWidth);
		m1 = y * (Scr.VyMax + Scr.MyDisplayHeight) / (icon_h * Scr.MyDisplayHeight);
		x = (x - n1) *
		    (Scr.VxMax + Scr.MyDisplayWidth) / (icon_w - n) - Scr.Vx;
		y = (y - m1) *
		    (Scr.VyMax + Scr.MyDisplayHeight) / (icon_h - m) - Scr.Vy;

		if (((t->flags & ICONIFIED) && (StickyIcons)) ||
		    (t->flags & STICKY)) {
			if (x > Scr.MyDisplayWidth - 16)
				x = Scr.MyDisplayWidth - 16;
			if (y > Scr.MyDisplayHeight - 16)
				y = Scr.MyDisplayHeight - 16;
			if (x + t->width < 16)
				x = 16 - t->width;
			if (y + t->height < 16)
				y = 16 - t->height;
		}
		if (moved) {
			if (t->flags & ICONIFIED)
				XMoveWindow(dpy, t->icon_w, x, y);
			else
				XMoveWindow(dpy, t->w, x, y);
			XSync(dpy, 0);
		} else {
			MoveResizePagerView(t);
		}
		SendInfo(fd, "Raise", t->w);

		if (t->flags & ICONIFIED)
			XSetInputFocus(dpy, t->icon_w, RevertToParent, Event->xbutton.time);
		else
			XSetInputFocus(dpy, t->w, RevertToParent, Event->xbutton.time);
	}

}
