/*
 * Copyright (C) 1998 Eric Tremblay <deltax@pragma.net>
 * Copyright (c) 1998 Doug Alcorn <alcornd@earthlink.net>
 * Copyright (C) 1998 Sasha Vasko <sashav@sprintmail.com>
 * Copyright (C) 1998 Makoto Kato <m_kato@ga2.so-net.ne.jp>
 * Copyright (C) 1998 Ric Lister <ric@giccs.georgetown.edu>
 * Copyright (C) 1997 Guylhem Aznar <guylhem@oeil.qc.ca>
 * 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.
 *
 */

/*
   #define LOG1(a)       fprintf( stderr, a );
   #define LOG2(a,b)    fprintf( stderr, a, b );
   #define LOG3(a,b,c)    fprintf( stderr, a, b, c );
   #define LOG4(a,b,c,d)    fprintf( stderr, a, b, c, d );
 */

#define LOG1(a)
#define LOG2(a,b)
#define LOG3(a,b,c)
#define LOG4(a,b,c,d)


#include "../../configure.h"

#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <time.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>
#ifdef SHAPE
#include <X11/extensions/shape.h>
#endif

#include "Pager.h"

#ifdef I18N
#ifdef __STDC__
#define XTextWidth(x,y,z)         XmbTextEscapement(x ## set,y,z)
#else
#define XTextWidth(x,y,z)         XmbTextEscapement(x/**/set,y,z)
#endif
#define XDrawString(t,u,v,w,x,y,z)      XmbDrawString(t,u,FONTSET,v,w,x,y,z)
#define XDrawImageString(t,u,v,w,x,y,z) XmbDrawString(t,u,FONTSET,v,w,x,y,z)
#endif

extern Display *dpy;

Pixel back_pix, fore_pix, grid_pix, hi_pix;
Pixel focus_pix;
Pixel focus_fore_pix;
extern int window_w, window_h, window_x, window_y, window_x_negative, window_y_negative,
  usposition, uselabel;
extern int StartIconic;
extern int icon_w, icon_h, icon_x, icon_y;
extern int LabelBelowDesk;
extern int HideInactiveLabel;
extern int different_grid_color, hilight_borders;

MyFont font, windowFont;

GC rvGC;
GC StdGC, FocusGC;

extern int StickyIcons;
static Atom wm_del_win;

extern char *MyName;

extern int TitleAlign;
extern int fd[2];

int desk_w = 0;
int desk_h = 0;
int scr_w = 0;
int scr_h = 0;
int label_h = 0;
int label_y = 0;
unsigned border_width = 1;
extern int DeskBorderWidth;
extern int PageSeparatorOn;
extern int FrameOn;


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 */

void 
InitDesk (long Desk)
{
  char line[100];
  LOG2 ("\nEnter InitDesk %ld", Desk);
  sprintf (line, "Desk %lu", Desk + Pager.desk1);
  CopyString (&Pager.Desks[Desk].label, line);

  Pager.Desks[Desk].LoaderArgs = NULL;
#ifdef PAGER_BACKGROUND
  InitDeskBackgrounds (Desk);
#endif
  Pager.Desks[Desk].PagerBackType = backgrUseXPM;
  Pager.Desks[Desk].FastBackgroundOn = 0;
  Pager.Desks[Desk].tile_hsize = 0;
  Pager.Desks[Desk].tile_vsize = 0;
  LOG2 ("\nExit InitDesk %ld", Desk);
}


/***********************************************************************
 *
 *  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 
CalcDeskSize ()
{
  desk_w = window_w / Pager.Columns - (DeskBorderWidth * 2);
  desk_h = window_h / Pager.Rows - label_h - DeskBorderWidth * 3;
  label_y = (LabelBelowDesk ? desk_h + DeskBorderWidth * 2 : 0);
}

void
initialize_pager (void)
{
  XTextProperty name;
  unsigned long valuemask;
  XSetWindowAttributes attributes;
  XWMHints wmhints;
  extern char *PagerFore, *PagerGridColor, *PagerBack, *HilightC;
  extern char *font_string, *smallFont;
  extern char *HiBack;
  extern char *HiFore;
  extern int FastStartup;
  extern int SetRootOnStartup;
  char *loadingName;
  int i, l;
  XGCValues gcv;
  unsigned long gcm;
  XClassHint class1;
  int bStarted = 0;

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

  /* load the font */

  if (uselabel)
    {
      load_font (font_string, &font);
      label_h = font.height + 2;
    }
  else
    {
      label_h = 0;
      load_font (NULL, &font);
    }

  if (smallFont != NULL)
    load_font (smallFont, &windowFont);
  else
    windowFont.font = NULL;

  /* Load the colors */
  fore_pix = GetColor (PagerFore);
  back_pix = GetColor (PagerBack);
  focus_pix = GetColor (HiBack);
  /* Revert to default behaviour if no PagerGridColor line was found in the config file */
  if (different_grid_color)
    grid_pix = GetColor (PagerGridColor);
  else
    grid_pix = fore_pix;

  focus_fore_pix = GetColor (HiFore);
  hi_pix = GetColor (HilightC);
#ifdef SHAPE
  /* We need SHAPE extensions to hide inactive lables. */
  if (HideInactiveLabel)
    {
      int s1, s2;
      HideInactiveLabel = (XShapeQueryExtension (dpy, &s1, &s2) ? 1 : 0);
    }
#endif

  /* 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 (Pager.Rows <= 0)
    {
      if (Pager.Columns <= 0)
	{
	  Pager.Columns = Pager.ndesks;
	  Pager.Rows = 1;
	}
      else
	{
	  Pager.Rows = Pager.ndesks / Pager.Columns;
	  if (Pager.Rows * Pager.Columns < Pager.ndesks)
	    Pager.Rows++;
	}
    }
  else if (Pager.Columns <= 0)
    {
      Pager.Columns = Pager.ndesks / Pager.Rows;
      if (Pager.Rows * Pager.Columns < Pager.ndesks)
	Pager.Columns++;
    }
  else if (Pager.Rows * Pager.Columns < Pager.ndesks)
    {
      Pager.Rows = Pager.ndesks / Pager.Columns;
      if (Pager.Rows * Pager.Columns < Pager.ndesks)
	Pager.Rows++;
    }

  LOG3 ("\nPager: Rows=%d, Columns=%d", Pager.Rows, Pager.Columns)
    CalcDeskSize ();
  if (window_w > 0)
    {
      window_w = (desk_w + DeskBorderWidth * 2) * Pager.Columns;
      if (window_w > 0)
	Scr.VScale = Pager.xSize / window_w;
    }
  if (window_h > 0)
    {
      window_h = (desk_h + label_h + DeskBorderWidth * 3) * Pager.Rows;
      if (window_h > label_h)
	Scr.VScale = Pager.ySize / (window_h - label_h - DeskBorderWidth * 3);
      else
	window_h = 0;
    }

  if (window_w <= 0)
    window_w = Pager.Columns * (Pager.xSize / Scr.VScale + (Pager.PageColumns - 1) + DeskBorderWidth * 2);
  if (window_h <= 0)
    window_h = Pager.Rows * (Pager.ySize / Scr.VScale + (Pager.PageRows - 1) + label_h + DeskBorderWidth * 3);

  if (window_x < 0 || (window_x == 0 && window_x_negative == 1))
    {
      sizehints.win_gravity = NorthEastGravity;
      window_x = Scr.MyDisplayWidth - window_w + window_x - 2;
    }
  if (window_y < 0 || (window_y == 0 && window_y_negative == 1))
    {
      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 = grid_pix;	/* was: 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 = Pager.Columns * Pager.PageColumns;
  sizehints.height_inc = Pager.Rows * Pager.PageRows;
  sizehints.base_width = Pager.Columns * (Pager.PageColumns * 2 - 1) + Pager.Columns * 2 - 1;
  sizehints.base_height = Pager.Rows * (Pager.PageRows * 2 + label_h) + Pager.PageRows * 2 - 1;
  sizehints.min_width = sizehints.base_width;
  sizehints.min_height = sizehints.base_height;

  Pager.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, Pager.Pager_w, &wm_del_win, 1);
  XSetWMNormalHints (dpy, Pager.Pager_w, &sizehints);

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

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

  icon_w = ((icon_w / Pager.PageColumns) + 1) * Pager.PageColumns - 1;
  icon_h = ((icon_h / Pager.PageRows) + 1) * (Pager.PageRows) - 1;
  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;

/* here indicating that we are still loading, so AS would not think that we are done already */
  loadingName = safemalloc (strlen (MyName) + 12 + 1);
  sprintf (loadingName, "Loading %s ...", MyName);
  class1.res_name = loadingName;
  class1.res_class = "ASModule";

  XSetWMProperties (dpy, Pager.Pager_w, &name, &name, NULL, 0,
		    &sizehints, &wmhints, &class1);
  free (loadingName);
  class1.res_name = MyName;	/* for future use */

  /* showing window to let user see that we are doing something */
  XMapRaised (dpy, Pager.Pager_w);

  CalcDeskSize ();

  valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
  attributes.border_pixel = grid_pix;	/* was: fore_pix */

  for (i = 0; i < Pager.ndesks; i++)
    {
      attributes.background_pixel = back_pix;
      attributes.event_mask = (ExposureMask | ButtonReleaseMask);

      Pager.Desks[i].title_w = XCreateWindow (dpy, Pager.Pager_w,
				      0, 0, desk_w, desk_h + label_h + 2, 1,
					      CopyFromParent,
					      InputOutput, CopyFromParent,
					      valuemask,
					      &attributes);
      XSetWindowBorderWidth (dpy, Pager.Desks[i].title_w, DeskBorderWidth);

      attributes.event_mask = (ExposureMask | ButtonReleaseMask |
			       ButtonPressMask | ButtonMotionMask);
      Pager.Desks[i].w = XCreateWindow (dpy, Pager.Desks[i].title_w, -1, label_h - 1, desk_w, desk_h, 1,
					CopyFromParent,
					InputOutput, CopyFromParent,
					valuemask, &attributes);
      XSetWindowBorderWidth (dpy, Pager.Desks[i].w, DeskBorderWidth);

#ifdef PAGER_BACKGROUND
      MakeBackgrounds (i);
      SetPagerBackground (i);
      if (i == 0)
	if (IfRootPixmap (i))
	  {
	    if (SetRootOnStartup)
	      DrawRoot (i);
	    else
	      SetERootPixmap (i);	/* we only needs to let Eterm know what 
					   background we are planning to use at this point */
	    /* which will be set later when AS signals us about 
	       current desk */
	    if (FastStartup)
	      {
		/* here remapping itself to let Afterstep know that we are finished with startup */
		XUnmapWindow (dpy, Pager.Pager_w);
		XSetWMProperties (dpy, Pager.Pager_w, &name, &name, NULL, 0,
				  &sizehints, &wmhints, &class1);
		XMapRaised (dpy, Pager.Pager_w);
		bStarted = 1;
	      }
	  }
#endif

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

      for (l = 0; l < 4 && FrameOn; l++)
	{

	  Pager.Desks[i].CPagerWin[l] = XCreateWindow (dpy, Pager.Desks[i].w, -1000, -1000, 1, 1, 0,
				CopyFromParent, InputOutput, CopyFromParent,
						    valuemask, &attributes);
	  XMapRaised (dpy, Pager.Desks[i].CPagerWin[l]);
	}
      XMapRaised (dpy, Pager.Desks[i].w);
      XMapRaised (dpy, Pager.Desks[i].title_w);
    }
  gcm = GCForeground | GCBackground | GCFont;
  gcv.foreground = grid_pix;	/* was: fore_pix */
  gcv.background = back_pix;

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

  gcv.foreground = hi_pix;
  if (Scr.d_depth < 2)
    {
      gcv.foreground = fore_pix;
      gcv.background = back_pix;
    }
  Scr.HiReliefGC = 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.font != NULL)
    {
      /* Create GC's for doing window labels */
      gcv.foreground = focus_fore_pix;
      gcv.background = focus_pix;
      gcv.font = windowFont.font->fid;
      StdGC = XCreateGC (dpy, Scr.Root, gcm, &gcv);

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

  if (!bStarted)
    {
      /* here remapping itself to let Afterstep know that we are finished with startup */
      XUnmapWindow (dpy, Pager.Pager_w);
      XSetWMProperties (dpy, Pager.Pager_w, &name, &name, NULL, 0,
			&sizehints, &wmhints, &class1);
      XMapRaised (dpy, Pager.Pager_w);
    }
  /* final cleanup */
  XFree ((char *) name.value);
  /* need to do this prior to resizing window to properly resie it ;) */
  XFlush (dpy);
  Pager.bStarted = 1;
  /* we need this to get right size of the Pager after all this mess above */
  XResizeWindow (dpy, Pager.Pager_w, window_w, window_h);

}

/****************************************************************************
 *
 * 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:
      ReConfigureEx (Event->xconfigure.width, Event->xconfigure.height,
		     Event->xconfigure.border_width);
      break;
    case Expose:
      HandleExpose (Event);
      break;
    case ButtonRelease:
      if ((Event->xbutton.button == 1) ||
	  (Event->xbutton.button == 2))		/*3)) ??????? see below */
	{
	  for (i = 0; i < Pager.ndesks; i++)
	    {
	      if (Event->xany.window == Pager.Desks[i].w)
		SwitchToDeskAndPage (i, Event);
	      if (Event->xany.window == Pager.Desks[i].title_w)
		SwitchToDesk (i);
	    }
	  if (Event->xany.window == icon_win)
	    IconSwitchPage (Event);
	}
      /* that was never going to happen ?!?!?! BUg??? */
      else if (Event->xbutton.button == 3)
	{
	  for (i = 0; i < Pager.ndesks; i++)
	    {
	      if (Event->xany.window == Pager.Desks[i].w)
		{
		  XQueryPointer (dpy, Pager.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 == 1) &&
	    (Event->xbutton.state & Mod1Mask))) &&
	  (Event->xbutton.subwindow != None))
	{
	  MoveWindow (Event);
	}
      else if (Event->xbutton.button == 3)
	{
	  for (i = 0; i < Pager.ndesks; i++)
	    {
	      if (Event->xany.window == Pager.Desks[i].w)
		{
		  XQueryPointer (dpy, Pager.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 < Pager.ndesks; i++)
	    {
	      if (Event->xany.window == Pager.Desks[i].w)
		{
		  XQueryPointer (dpy, Pager.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 < Pager.ndesks; i++)
    {
      if ((Event->xany.window == Pager.Desks[i].w)
	  || (Event->xany.window == Pager.Desks[i].title_w))
	DrawGrid (i, 0);
    }
  if (Event->xany.window == icon_win)
    DrawIconGrid (0);

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

/****************************************************************************
 *
 * These function will display and hide frame around desk in Pager window
 * frame consist of 4 windows forming sides of the Box
 *
 ****************************************************************************/
void 
DisplayFrame (long Desk)
{
  int x, y;

  if (FrameOn == 0)
    return;
  x = (desk_w - Pager.PageColumns + 1) * Scr.Vx / Pager.xSize + (Scr.Vx / Scr.MyDisplayWidth);
  y = (desk_h - Pager.PageRows + 1) * Scr.Vy / Pager.ySize + (Scr.Vy / Scr.MyDisplayHeight);

  XMoveResizeWindow (dpy, Pager.Desks[Desk].CPagerWin[0], x - 2, y - 2, scr_w + 5, 3);
  XMoveResizeWindow (dpy, Pager.Desks[Desk].CPagerWin[1], x - 2, y + scr_h, scr_w + 5, 3);
  XMoveResizeWindow (dpy, Pager.Desks[Desk].CPagerWin[2], x - 2, y, 3, scr_h);
  XMoveResizeWindow (dpy, Pager.Desks[Desk].CPagerWin[3], x + scr_w, y, 3, scr_h);

  LowerFrame (Desk);
}

void 
LowerFrame (long Desk)
{
  int i;
  if (FrameOn == 0)
    return;
  for (i = 0; i < 4; i++)
    XLowerWindow (dpy, Pager.Desks[Desk].CPagerWin[i]);
}

void 
HideFrame (long Desk)
{
  int i;
  if (FrameOn == 0)
    return;
  for (i = 0; i < 4; i++)
    XMoveWindow (dpy, Pager.Desks[Desk].CPagerWin[i], -1000, -1000);
}
#ifdef SHAPE
/* Update window shaping when using HideInactiveLabels */
/* the following code needs some consideration */
void 
UpdateWindowShape ()
{
  int i, j, desk_cnt;
  XRectangle *shape = 0;
  int desk_pos_x = -1, desk_pos_y = -1, vis_desk_w, vis_desk_h;
  int squares_num = Pager.ndesks + 1;

  if (!HideInactiveLabel || !uselabel || label_h <= 0)
    return;
  if ((shape = alloca (squares_num * sizeof (XRectangle))) == NULL)
    return;

  if (Scr.CurrentDesk > Pager.desk2 || Scr.CurrentDesk < Pager.desk1)
    squares_num = Pager.ndesks;

  desk_cnt = 0;
  vis_desk_w = desk_w + DeskBorderWidth * 2;
  vis_desk_h = desk_h + DeskBorderWidth * 3;
  desk_pos_y = (LabelBelowDesk ? 0 : label_h);
  for (i = 0; i < Pager.Rows; i++)
    {
      desk_pos_x = 0;
      for (j = 0; j < Pager.Columns; j++)
	{
	  if (desk_cnt < Pager.ndesks)
	    {
	      shape[desk_cnt].x = desk_pos_x;
	      shape[desk_cnt].y = desk_pos_y;
	      shape[desk_cnt].width = vis_desk_w;
	      shape[desk_cnt].height = vis_desk_h;

	      if (desk_cnt == Scr.CurrentDesk - Pager.desk1)
		{
		  shape[Pager.ndesks].x = desk_pos_x;
		  shape[Pager.ndesks].y = desk_pos_y + label_y - (LabelBelowDesk ? 0 : label_h + DeskBorderWidth * 2);
		  shape[Pager.ndesks].width = vis_desk_w;
		  shape[Pager.ndesks].height = label_h + DeskBorderWidth * 2;
		}
	    }
	  desk_pos_x += vis_desk_w;
	  desk_cnt++;
	}
      desk_pos_y += vis_desk_h + label_h;
    }
  XShapeCombineRectangles (dpy, Pager.Pager_w, ShapeBounding, 0, 0,
			   shape, squares_num, ShapeSet, 0);
}
#endif

/****************************************************************************
 *
 * Respond to a change in window geometry.
 *
 ****************************************************************************/
void 
ReConfigure (void)
{
  Window root;
  unsigned width, height, bord_width, depth;
  int dum;

  XGetGeometry (dpy, Pager.Pager_w, &root, &dum, &dum,
		(unsigned *) &width, (unsigned *) &height,
		&bord_width, &depth);

  ReConfigureEx (width, height, bord_width);
}

void 
ReConfigureEx (unsigned width, unsigned height, unsigned bord_width)
{
  int i = 0, j, k, desk_pos_x = -1, desk_pos_y = 0;
  PagerWindow *t;

  if (!Pager.bStarted)
    return;
  if (width == window_w && height == window_h)
    return;			/* nothing to be done */

  LOG2 ("\n\n Pager: border width = %d, ", border_width)
    LOG3 ("width = %d, height = %d", window_w, window_h)

    border_width = bord_width;
  window_w = width;
  window_h = height;

  CalcDeskSize ();

  scr_w = (desk_w - Pager.PageColumns + 1) / Pager.PageColumns;
  scr_h = (desk_h - Pager.PageRows + 1) / Pager.PageRows;

  for (k = 0; k < Pager.Rows; k++)
    {
      desk_pos_x = 0;
      for (j = 0; j < Pager.Columns; j++)
	{
	  if (i < Pager.ndesks)
	    {
	      XMoveResizeWindow (dpy, Pager.Desks[i].title_w,
				 desk_pos_x, desk_pos_y, desk_w, desk_h + label_h + DeskBorderWidth);
	      XMoveResizeWindow (dpy, Pager.Desks[i].w,
				 0 - DeskBorderWidth, (LabelBelowDesk ? (0 - DeskBorderWidth) : (label_h - DeskBorderWidth)), desk_w, desk_h + DeskBorderWidth);
	      /* do we really need to do this here ??? */
	      if (i == Scr.CurrentDesk - Pager.desk1)
		DisplayFrame (i);
	      else
		HideFrame (i);

#ifdef PAGER_BACKGROUND
	      if (ScalePagerBackground (i))
		SetPagerBackground (i);
#endif
	      XClearArea (dpy, Pager.Desks[i].w, 0, 0, desk_w, desk_h, True);
	      if (uselabel)
		XClearArea (dpy, Pager.Desks[i].title_w, 0, label_y, desk_w, label_h, True);

	    }
	  desk_pos_x += desk_w + DeskBorderWidth * 2;
	  i++;
	}
      desk_pos_y += desk_h + label_h + DeskBorderWidth * 3;
    }
#ifdef SHAPE
  /* Update window shapes. */
  UpdateWindowShape ();
#endif

  /* reconfigure all the subordinate windows */
  for (t = Pager.Start; t != NULL; t = t->next)
    MoveResizePagerView (t);
}

void 
MovePage (void)
{
  int i;
  XTextProperty name;
  char str[64], *sptr;
  static int icon_desk_shown = -1000;

  Wait = 0;

  for (i = 0; i < Pager.ndesks; i++)
    if (i == Scr.CurrentDesk - Pager.desk1)
      DisplayFrame (i);
    else
      HideFrame (i);

  DrawIconGrid (1);
  ReConfigureIcons ();

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

      if ((Scr.CurrentDesk >= Pager.desk1) && (Scr.CurrentDesk <= Pager.desk2))
	sptr = Pager.Desks[Scr.CurrentDesk - Pager.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, Pager.Pager_w, &name);
    }
}

void 
GetViewPosition (PagerWindow * t, PagerViewPosition * pos)
{
  int abs_x, abs_y, n, m, n1, m1;

  n = Pager.PageColumns - 1;	/* number of grid lines */
  m = Pager.PageRows - 1;
  n1 = (Scr.Vx + t->x) / Scr.MyDisplayWidth;	/* number of pages before */
  m1 = (Scr.Vy + t->y) / Scr.MyDisplayHeight;

  abs_x = Scr.Vx + t->x;	/* absolute coordinate within the desk */
  abs_y = Scr.Vy + t->y;

  pos->normal_x = abs_x * (desk_w - n) / Pager.xSize;
  pos->normal_y = abs_y * (desk_h - m) / Pager.ySize;

  pos->normal_width = (abs_x + t->width + 2) * (desk_w - n) / Pager.xSize - 2 - pos->normal_x;
  pos->normal_height = (abs_y + t->height + 2) * (desk_h - m) / Pager.ySize - 2 - pos->normal_y;

  pos->normal_x += n1;		/* offset to number of grid lines */
  pos->normal_y += m1;

  if (pos->normal_width < 1)
    pos->normal_width = 1;
  if (pos->normal_height < 1)
    pos->normal_height = 1;

  pos->icon_x = abs_x * (icon_w - n) / Pager.xSize;
  pos->icon_y = abs_y * (icon_h - m) / Pager.ySize;
  pos->icon_width = (abs_x + t->width + 2) * (icon_w - n) / Pager.xSize - 2 - pos->icon_x;
  pos->icon_height = (abs_y + t->height + 2) * (icon_h - m) / Pager.ySize - 2 - pos->icon_y;

  pos->icon_x += n1;
  pos->icon_y += m1;

  if (pos->icon_width < 1)
    pos->icon_width = 1;
  if (pos->icon_height < 1)
    pos->icon_height = 1;

}

void 
ReConfigureIcons (void)
{
  PagerWindow *t;
  PagerViewPosition pos;

  for (t = Pager.Start; t != NULL; t = t->next)
    if (t->IconView != None)
      {
	if (Scr.CurrentDesk == t->desk)
	  {
	    GetViewPosition (t, &pos);
	    XMoveResizeWindow (dpy, t->IconView,
		   pos.icon_x, pos.icon_y, pos.icon_width, pos.icon_height);
	  }
	else
	  XMoveWindow (dpy, t->IconView, -1000, -1000);
      }
}


/****************************************************************************
 *
 * Draw grid lines for desk #i
 *
 ****************************************************************************/
void 
DrawGrid (int i /*Desk */ , int erase)
{
  int pos;
  int d, hor_off, w;
  char str[16], *ptr;

  if ((i < 0) || (i >= Pager.ndesks))
    return;
  if (PageSeparatorOn)
    {
      for (d = 1; d < Pager.PageColumns; d++)
	{
	  pos = d * desk_w / Pager.PageColumns;
	  XDrawLine (dpy, Pager.Desks[i].w, Scr.NormalGC, pos, 0, pos, desk_h);
	}
      for (d = 1; d < Pager.PageRows; d++)
	{
	  pos = d * desk_h / Pager.PageRows;
	  XDrawLine (dpy, Pager.Desks[i].w, Scr.NormalGC, 0, pos, desk_w, pos);
	}
    }


  if (uselabel && label_h > 0)
    {
      d = Pager.desk1 + i;
      if (Scr.CurrentDesk == d)
	XFillRectangle (dpy, Pager.Desks[i].title_w, Scr.HiReliefGC,
			0, label_y,
			desk_w, label_h);
      else if (erase)
	XClearArea (dpy, Pager.Desks[i].title_w, 0, label_y, desk_w, label_h, False);

      ptr = Pager.Desks[i].label;
      w = XTextWidth (font.font, ptr, strlen (ptr));
      if (w > desk_w)
	{
	  sprintf (str, "%d", d);
	  ptr = str;
	  w = XTextWidth (font.font, ptr, strlen (ptr));
	}

      if (w <= desk_w)
	{
#undef FONTSET
#define FONTSET font.fontset

	  if (TitleAlign > 0)
	    hor_off = TitleAlign;
	  else if (TitleAlign == 0)
	    hor_off = (desk_w - w) / 2;
	  else
	    hor_off = desk_w - w + TitleAlign;

	  XDrawString (dpy, Pager.Desks[i].title_w,
		       (d == Scr.CurrentDesk) ? rvGC : Scr.NormalGC,
		       hor_off, label_y + font.y, ptr, strlen (ptr));
	}
    }
#ifdef SHAPE
  /* Update window shapes. */
  UpdateWindowShape ();
#endif

}

void 
DrawIconGrid (int erase)
{
  int y, x, w, h;
  int i;

  if (erase)
    XClearWindow (dpy, icon_win);

  if (PageSeparatorOn)
    {
      for (i = 1; i < Pager.PageColumns; i++)
	{
	  x = i * icon_w / Pager.PageColumns;
	  XDrawLine (dpy, icon_win, Scr.NormalGC, x, 0, x, icon_h);
	}
      for (i = 1; i < Pager.PageRows; i++)
	{
	  y = i * icon_h / Pager.PageRows;
	  XDrawLine (dpy, icon_win, Scr.NormalGC, 0, y, icon_w, y);
	}
    }

  w = icon_w - Pager.PageColumns - 1;	/* icon desk size - grid lines num */
  h = icon_h - Pager.PageRows - 1;

  x = w * Scr.Vx / Pager.xSize + Scr.Vx / Scr.MyDisplayWidth;
  y = h * Scr.Vy / Pager.ySize + Scr.Vy / Scr.MyDisplayHeight;

  XFillRectangle (dpy, icon_win, Scr.HiReliefGC, x, y, w / Pager.PageColumns, h / Pager.PageRows);
}

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

  sprintf (command, "Desk 0 %d\n", Desk + Pager.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 * Pager.xSize / (desk_w * Scr.MyDisplayWidth),
	   Event->xbutton.y * Pager.ySize / (desk_h * Scr.MyDisplayHeight));
  SendInfo (fd, command, 0);

  if (Scr.CurrentDesk == Desk + Pager.desk1)	/* just changing page */
    sprintf (command, "Desk 0 %d\n", Desk + Pager.desk1);
  else				/* really changing desk */
    sprintf (command, "Desk 10000 %d\n", Desk + Pager.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 * Pager.xSize / (icon_w * Scr.MyDisplayWidth),
	   Event->xbutton.y * Pager.ySize / (icon_h * Scr.MyDisplayHeight));
  SendInfo (fd, command, 0);
#endif
  Wait = 1;
}

void 
DestroyIconView (PagerWindow * t)
{
  if (t != NULL)
    if (t->IconView != None)
      {
	balloon_delete (balloon_find (t->IconView));
	XDestroyWindow (dpy, t->IconView);
	t->IconView = None;
      }
}

void 
DestroyView (PagerWindow * t)
{
  if (t != NULL)
    if (t->PagerView != None)
      {
	balloon_delete (balloon_find (t->PagerView));
	XDestroyWindow (dpy, t->PagerView);
	t->PagerView = None;
      }
  DestroyIconView (t);
}

void
AddNewWindow (PagerWindow * t)
{
  unsigned long valuemask;
  XSetWindowAttributes attributes;
  PagerViewPosition pos;
  int i;			/* Desk */

  if (t == NULL)
    return;
  if (t->desk < Pager.desk1 || t->desk > Pager.desk2)
    {
      t->IconView = None;
      t->PagerView = None;
      return;
    }

  i = t->desk - Pager.desk1;
  GetViewPosition (t, &pos);

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

  /* Enter and Leave events to pop up balloon window */
  attributes.event_mask = (ExposureMask | EnterWindowMask | LeaveWindowMask);

  if ((t->PagerView = XCreateWindow (dpy, Pager.Desks[i].w,
	 pos.normal_x, pos.normal_y, pos.normal_width, pos.normal_height, 1,
				     CopyFromParent,
				     InputOutput, CopyFromParent,
				     valuemask, &attributes)) != None)
    {

      balloon_new_with_text (dpy, t->PagerView, t->icon_name);
      XMapRaised (dpy, t->PagerView);

      if (Scr.CurrentDesk != t->desk)
	{
	  pos.icon_x = -1000;	/* showing only windows on active desk if iconized */
	  pos.icon_y = -1000;
	}

      if ((t->IconView = XCreateWindow (dpy, icon_win, pos.icon_x, pos.icon_y,
					pos.icon_width, pos.icon_height, 1,
					CopyFromParent,
					InputOutput, CopyFromParent,
					valuemask, &attributes)) != None)
	{
	  if (Scr.CurrentDesk == t->desk)
	    XGrabButton (dpy, 2, AnyModifier, t->IconView,
	       True, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
			 GrabModeAsync, GrabModeAsync, None,
			 None);
	  balloon_new_with_text (dpy, t->IconView, t->icon_name);
	  XMapRaised (dpy, t->IconView);

	}

      Hilight (t, OFF);
    }				/* PagerView != None */
}

void 
ChangeDeskForWindow (PagerWindow * t, long newdesk)
{
  PagerViewPosition pos;

  if (t == NULL || newdesk == 10000)
    return;
  if (newdesk < Pager.desk1 || newdesk > Pager.desk2)
    {
      DestroyView (t);
      return;
    }

  LOG3 ("\n Changing Window [%ld] Desk to desk : %ld", t->w, (newdesk - Pager.desk1))
    if (t->PagerView == None || t->IconView == None)
    {
      t->desk = newdesk;
      DestroyView (t);
      AddNewWindow (t);
      LOG2 ("\n  adding new window to desk : %ld", (newdesk - Pager.desk1))
	return;
    }

  GetViewPosition (t, &pos);
  XReparentWindow (dpy, t->PagerView, Pager.Desks[newdesk - Pager.desk1].w,
		   pos.normal_x, pos.normal_y);
  XResizeWindow (dpy, t->PagerView, pos.normal_width, pos.normal_height);

  t->desk = newdesk;
  if (Scr.CurrentDesk == newdesk)
    XMoveResizeWindow (dpy, t->IconView, pos.icon_x, pos.icon_y,
		       pos.icon_width, pos.icon_height);
  else
    XMoveWindow (dpy, t->IconView, -1000, -1000);
}

void 
MoveResizePagerView (PagerWindow * t)
{
  PagerViewPosition pos;

  if (t == NULL)
    return;
  if (t->desk < Pager.desk1 || t->desk > Pager.desk2)
    return;

  if (t->PagerView == None || t->IconView == None)
    {
      DestroyView (t);
      AddNewWindow (t);
      return;
    }

  GetViewPosition (t, &pos);

/*LOG3( "\n Resizing window [%ld:%s] to:\n",  t->w, t->icon_name )
   LOG3( "x=%d, y=%d, ", pos.normal_x, pos.normal_x )
   LOG3( "width=%d, height=%d.\n", pos.normal_width, pos.normal_height )
   LOG3( "Original width=%d, height=%d.", t->width, t->height ) */

  XMoveResizeWindow (dpy, t->PagerView, pos.normal_x, pos.normal_y,
		     pos.normal_width, pos.normal_height);

  if (Scr.CurrentDesk == t->desk)
    XMoveResizeWindow (dpy, t->IconView, pos.icon_x, pos.icon_y,
		       pos.icon_width, pos.icon_height);
  else
    XMoveWindow (dpy, t->IconView, -1000, -1000);
}

void 
MoveStickyWindows (void)
{
  PagerWindow *t;

  if (Scr.CurrentDesk != 10000)
    for (t = Pager.Start; t != NULL; t = t->next)
      if (t->flags & STICKY || ((t->flags & ICONIFIED) && StickyIcons))
	{
	  LOG3 ("\n Moving sticky window [%ld:%s]: ", t->w, t->icon_name)
	    if (t->desk != Scr.CurrentDesk)
	    {
	      LOG2 (" Changing Desk to [%d]", Scr.CurrentDesk)
		ChangeDeskForWindow (t, Scr.CurrentDesk);
	    }
	  else
	    {
	      LOG1 (" Resizing Window to a new page")
		MoveResizePagerView (t);
	    }
	}
}

void 
Hilight (PagerWindow * t, int on)
{
  Pixmap back_p;
  Pixel back_color;
  if (t == NULL)
    return;
  if (Scr.d_depth < 2)
    {
      if (on)
	back_p = Scr.gray_pixmap;
      else if (t->flags & STICKY)
	back_p = Scr.sticky_gray_pixmap;
      else
	back_p = Scr.light_gray_pixmap;

      if (t->PagerView != None)
	XSetWindowBackgroundPixmap (dpy, t->PagerView, back_p);
      if (t->IconView != None)
	XSetWindowBackgroundPixmap (dpy, t->IconView, back_p);

    }
  else
    {
      if (on)
	back_color = focus_pix;
      else
	back_color = t->back;

      if (t->PagerView != None)
	XSetWindowBackground (dpy, t->PagerView, back_color);
      if (t->IconView != None)
	XSetWindowBackground (dpy, t->IconView, back_color);
      /* hilight_borders tells us to also highlight the frame of the focused window. */
      if (hilight_borders)
	{
	  XSetWindowAttributes attributes;
	  attributes.border_pixel = (on ? focus_fore_pix : fore_pix);
	  if (t->PagerView != None)
	    XChangeWindowAttributes (dpy, t->PagerView, CWBorderPixel, &attributes);
	  if (t->IconView != None)
	    XChangeWindowAttributes (dpy, t->IconView, CWBorderPixel, &attributes);
	}			/* if */
    }

  if (t->PagerView != None)
    XClearWindow (dpy, t->PagerView);
  if (t->IconView != None)
    XClearWindow (dpy, t->IconView);

  LabelWindow (t);
  LabelIconWindow (t);
}

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

      sx = (100 * (x * Pager.xSize / win_w - Scr.Vx)) / Scr.MyDisplayWidth;
      sy = (100 * (y * Pager.ySize / win_h - Scr.Vy)) / Scr.MyDisplayHeight;
      if (sx > 100)
	sx = 100;
      else if (sx < -100)
	sx = -100;
      if (sy < -100)
	sy = -100;
      else if (sy > 100)
	sy = 100;

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

void 
Scroll (int Desk, int x, int y)
{
  if (Desk != Scr.CurrentDesk)
    return;
  ScrollInWindow (x, y, desk_w, desk_h);
}

void 
IconScroll (int x, int y)
{
  ScrollInWindow (x, y, icon_w, icon_h);
}

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;

  for (t = Pager.Start; t != NULL; t = t->next)
    if (t->PagerView == Event->xbutton.subwindow)
      break;

  if (t == NULL)
    {
      for (t = Pager.Start; t != NULL; t = t->next)
	if (t->IconView == Event->xbutton.subwindow)
	  break;

      if (t != NULL)
	IconMoveWindow (Event, t);
      return;
    }

  if (t->desk < Pager.desk1 || t->desk > Pager.desk2)
    return;

  NewDesk = t->desk - Pager.desk1;
  n = Pager.PageColumns - 1;
  m = Pager.PageRows - 1;
  n1 = (Scr.Vx + t->x) / Scr.MyDisplayWidth;
  m1 = (Scr.Vy + t->y) / Scr.MyDisplayHeight;
  wx = (Scr.Vx + t->x) * (desk_w - n) / Pager.xSize + n1;
  wy = (Scr.Vy + t->y) * (desk_h - m) / Pager.ySize + m1;
  wx1 = wx + (desk_w + 1) * (NewDesk % Pager.Columns);
  wy1 = wy + label_h + (desk_h + label_h + 1) * (NewDesk / Pager.Columns);

  XReparentWindow (dpy, t->PagerView, Pager.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, Pager.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, Pager.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 && 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, Pager.xSize, Pager.ySize);
	  XSync (dpy, 0);
	  sprintf (command, "WindowsDesk %d", NewDesk);
	  SendInfo (fd, command, t->w);
	  t->desk = NewDesk;
	}
      if (NewDesk >= Pager.desk1 && NewDesk <= Pager.desk2)
	XReparentWindow (dpy, t->PagerView, Pager.Desks[NewDesk - Pager.desk1].w, 0, 0);
      else
	DestroyView (t);

      XTranslateCoordinates (dpy, Pager.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) * Pager.Columns;
      if ((NewDesk < 0) || (NewDesk >= Pager.ndesks))
	{
	  NewDesk = Scr.CurrentDesk - Pager.desk1;
	  x = xi;
	  y = yi;
	  moved = 0;
	}
      XTranslateCoordinates (dpy, Pager.Pager_w, Pager.Desks[NewDesk].w,
			     x - x1, y - y1, &x2, &y2, &dumwin);

      n1 = x2 * Pager.xSize / (desk_w * Scr.MyDisplayWidth);
      m1 = y2 * Pager.ySize / (desk_h * Scr.MyDisplayHeight);
      x = (x2 - n1) * Pager.xSize / (desk_w - n) - Scr.Vx;
      y = (y2 - m1) * Pager.ySize / (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 > Pager.xSize)
	x = Pager.xSize - t->frame_width - Scr.Vx;
      if (y + Scr.Vy > Pager.ySize)
	y = Pager.ySize - t->frame_height - Scr.Vy;
      if (((t->flags & ICONIFIED) && (StickyIcons)) ||
	  (t->flags & STICKY))
	{
	  NewDesk = Scr.CurrentDesk - Pager.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 + Pager.desk1 != t->desk)
	{
	  if (((t->flags & ICONIFIED) && (StickyIcons)) ||
	      (t->flags & STICKY))
	    {
	      NewDesk = Scr.CurrentDesk - Pager.desk1;
	      if (t->desk != Scr.CurrentDesk)
		ChangeDeskForWindow (t, Scr.CurrentDesk);
	    }
	  else
	    {
	      sprintf (command, "WindowsDesk %d", NewDesk + Pager.desk1);
	      SendInfo (fd, command, t->w);
	      t->desk = NewDesk + Pager.desk1;
	    }
	}
      if (NewDesk >= 0 && NewDesk < Pager.ndesks)
	{
	  XReparentWindow (dpy, t->PagerView, Pager.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);
	}
    }
}

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;
  if (t->IconView == None)
    return;

  n = Pager.PageColumns - 1;
  m = Pager.PageRows - 1;
  n1 = (Scr.Vx + t->x) / Scr.MyDisplayWidth;
  m1 = (Scr.Vy + t->y) / Scr.MyDisplayHeight;
  wx = (Scr.Vx + t->x) * (icon_w - n) / Pager.xSize + n1;
  wy = (Scr.Vy + t->y) * (icon_h - m) / Pager.ySize + 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 && 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);
      XUngrabPointer (dpy, CurrentTime);
      XSync (dpy, 0);

      if (t->flags & ICONIFIED)
	SendInfo (fd, "Move", t->icon_w);
      else
	SendInfo (fd, "Move", t->w);

    }
  else
    {
      x = x - x1;
      y = y - y1;
      n1 = x * Pager.xSize / (icon_w * Scr.MyDisplayWidth);
      m1 = y * Pager.ySize / (icon_h * Scr.MyDisplayHeight);
      x = (x - n1) * Pager.xSize / (icon_w - n) - Scr.Vx;
      y = (y - m1) * Pager.ySize / (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);
    }
}


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

  if (t == NULL)
    return;
  if (t->PagerView == None || t->icon_name == NULL || windowFont.font == NULL)
    return;

  if (t == Pager.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->PagerView);
#undef FONTSET
#define FONTSET windowFont.fontset
  XDrawImageString (dpy, t->PagerView, tgc, 2, windowFont.y + 2,
		    t->icon_name, strlen (t->icon_name));

}

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

  if (t == NULL)
    return;
  if (t->IconView == None || t->icon_name == NULL || windowFont.font == NULL)
    return;

  if (t == Pager.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);
#undef FONTSET
#define FONTSET windowFont.fontset
  XDrawImageString (dpy, t->IconView, tgc, 2, windowFont.y + 2,
		    t->icon_name, strlen (t->icon_name));

}

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