/* 
   PXKDrawingEngine.m

   Copyright (C) 1996 Free Software Foundation, Inc.

   Author:  Pascal Forget <pascal@wsc.com>
   Date: March 1996
   
   This file is part of the GNUstep GUI X/DPS Backend.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
   
   This library 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
   Library General Public License for more details.

   If you are interested in a warranty or support for this source code,
   contact Scott Christley <scottc@net-community.com> for more information.
   
   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ 

#include <gnustep/xdps/PXKit.h>

LogFile *logFile;

#define PXKDE_DEBUG 1

#define PXK_MAX(x,y) (x>y)?x:y

//
// This functions performs all backend initialization
// that is required before main() is called
//
BOOL
initialize_gnustep_backend()
{
  // Open log file
  logFile = [[LogFile alloc] initFile:"NSLog.log"];
  if (!logFile) abort();

  // Have backend classes poseAs their super
  NSLog(@"Using GNUstep GUI X/DPS Backend for backend implementation.\n");

  [PXKDPSContext poseAs:[NSDPSContext class]];
  [PXKScreen poseAs:[NSScreen class]];

  [PXKResponder poseAs:[NSResponder class]];
  [PXKEvent poseAs:[NSEvent class]];
  [PXKApplication poseAs:[NSApplication class]];
  [PXKView poseAs:[NSView class]];

  [PXKCell poseAs:[NSCell class]];
  [PXKControl poseAs:[NSControl class]];
  [PXKMatrix poseAs:[NSMatrix class]];
  [PXKWindow poseAs:[NSWindow class]];
  [PXKMenu poseAs:[NSMenu class]];
  [PXKPanel poseAs:[NSPanel class]];

  [PXKActionCell poseAs:[NSActionCell class]];
  [PXKFontManager poseAs:[NSFontManager class]];

  [PXKFont poseAs:[NSFont class]];
  [PXKFontPanel poseAs:[NSFontPanel class]];
  [PXKMenuCell poseAs:[NSMenuCell class]];

  [PXKColor poseAs:[NSColor class]];

  [PXKBox poseAs:[NSBox class]];
  [PXKButtonCell poseAs:[NSButtonCell class]];
  [PXKButton poseAs:[NSButton class]];

  [PXKSavePanel poseAs:[NSSavePanel class]];
  [PXKOpenPanel poseAs:[NSOpenPanel class]];

  [PXKPopUpButton poseAs:[NSPopUpButton class]];
  [PXKSliderCell poseAs:[NSSliderCell class]];
  [PXKSlider poseAs:[NSSlider class]];
  [PXKTextFieldCell poseAs:[NSTextFieldCell class]];
  [PXKText poseAs:[NSText class]];
  [PXKTextField poseAs:[NSTextField class]];

  // Initialize the XWindows drawing engine
  NSLog(@"Initializing XWindows drawing engine\n");
  initializeDrawingEngine();

  // success
  return YES;
}

void
pxkDebugMsg(const char *msg)
{
#if PXKDE_DEBUG    
    fprintf(stderr, "%s\n", msg);
#endif    
}

#if 0
#define icon_bitmap_width 40
#define icon_bitmap_height 40
static char icon_bitmap_bits[] = {
   0xc3, 0xc3, 0x7f, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
   0x00, 0x00, 0x80, 0x38, 0x00, 0x40, 0x00, 0x80, 0x24, 0x00, 0x00, 0x00,
   0x80, 0x44, 0x00, 0x00, 0x00, 0x80, 0x44, 0x00, 0x00, 0x00, 0x80, 0x74,
   0x00, 0x0f, 0x0c, 0x00, 0x7c, 0x3e, 0x41, 0x0e, 0x00, 0x44, 0x22, 0x41,
   0x02, 0x00, 0x84, 0x22, 0x46, 0x02, 0x00, 0x9c, 0x26, 0xcc, 0x02, 0x00,
   0x78, 0x3c, 0xcd, 0x36, 0x80, 0x00, 0x20, 0x06, 0x0c, 0x80, 0x01, 0x00,
   0x00, 0x00, 0x80, 0x01, 0x02, 0x40, 0x00, 0x80, 0x01, 0x06, 0x40, 0x00,
   0x80, 0x01, 0x04, 0x20, 0x00, 0x80, 0x01, 0x04, 0x20, 0x01, 0x80, 0x01,
   0x04, 0x20, 0x00, 0x80, 0x01, 0x04, 0x22, 0x00, 0x80, 0x01, 0x04, 0x33,
   0xf1, 0x81, 0x01, 0x88, 0x12, 0x31, 0x03, 0x01, 0x88, 0x12, 0x11, 0x02,
   0x00, 0x88, 0x12, 0x11, 0x02, 0x00, 0x48, 0x1a, 0x11, 0x02, 0x00, 0x70,
   0x04, 0x19, 0x82, 0x01, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x38,
   0x80, 0x01, 0x00, 0x00, 0xce, 0x80, 0x01, 0x00, 0x00, 0x83, 0x81, 0x81,
   0x07, 0x80, 0x01, 0x81, 0xe1, 0x04, 0xc0, 0x00, 0x83, 0x31, 0x08, 0x40,
   0x00, 0x82, 0x10, 0x08, 0x20, 0x00, 0x82, 0x19, 0x10, 0x30, 0x00, 0x86,
   0x0c, 0x30, 0x18, 0x00, 0x84, 0x04, 0x60, 0x0e, 0x00, 0xdc, 0x02, 0x80,
   0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00};
#endif

static char icon_bitmap_bits2[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/*
 * Below are declarations of the drawing engine's global variables.
 */

/* Contains a list of all views and windows created */
NSMutableArray *views;

NSColor *currentColor;

Display *pxkDisplay;
/* int pxkScreen; */
/* int pxkDisplayWidth; */
int pxkDisplayHeight;

GC pxkBlackGC;         /* Global drawing contexts for the most commonly      */
GC pxkWhiteGC;         /* used colors: Black, White, Light Gray, and         */
GC pxkLightgrayGC;     /* Dark Gray.  The drawing engine is smart            */
GC pxkDarkgrayGC;      /* enough to use these contexts when passed NSColors  */
                       /* that either have grayscale or RGB backings that    */
                       /* correspond to any of these predefined contexts.    */

@interface PXKXWindow : NSObject
{}
@end
@implementation PXKXWindow
@end

/* Private functions */

void
load_font(XFontStruct **font_info)
{
    char *fontname = "9x15";

    /* Load font and get font information structure. */
    if ((*font_info = XLoadQueryFont(pxkDisplay,fontname)) == NULL)
    {
	(void) fprintf( stderr, "Drawing Engine error: cannot open"
			" 9x15 font\n");
	exit( -1 );
    }
}

/* End Private Functions */

/*
 * initializeDrawingSystem() is called once from the NSApplication object
 * when the application starts
 */

int
initializeDrawingEngine(void)
{
    char *displayName = NULL;
    XGCValues values;
    unsigned long valuemask = (GCForeground | GCBackground);
    Window win;
    XColor c1, c2;
    int xscreen;
    NSRect r;
    GC xgc;

    if ( (pxkDisplay = XOpenDisplay(displayName)) == NULL ) {
	(void)fprintf(stderr, "Cannot connect to X server.  exiting.\n");
	exit(-1);
    }

    [(PXKDPSContext *)[NSDPSContext currentContext] setXDisplay: pxkDisplay];

    // pxkScreen = DefaultScreen(pxkDisplay);
    [(PXKScreen *)[NSScreen mainScreen] setXScreen: DefaultScreen(pxkDisplay)];
    xscreen = [(PXKScreen *)[NSScreen mainScreen] xScreen];

    r = [[NSScreen mainScreen] frame];
    printf("Display width: %f height: %f\n", r.size.width, r.size.height);
    
    /* createSystemImages(); */

    /*
     * Create the standard graphic contexts
     */

    win = RootWindow(pxkDisplay, xscreen);

    values.foreground = BlackPixel(pxkDisplay, xscreen);
    values.background = WhitePixel(pxkDisplay, xscreen);
    xgc = XCreateGC(pxkDisplay, win, valuemask, &values);
    [(PXKDPSContext *)[NSDPSContext currentContext] setGC: xgc];
    
    values.foreground = BlackPixel(pxkDisplay, xscreen);
    values.background = WhitePixel(pxkDisplay, xscreen);
    
    pxkBlackGC = XCreateGC(pxkDisplay, win, valuemask, &values);

    values.foreground = values.background;
    values.background = BlackPixel(pxkDisplay, xscreen);
    
    pxkWhiteGC = XCreateGC(pxkDisplay, win, valuemask, &values);

    /* set drawing color to lightgray */
    XAllocNamedColor(pxkDisplay,
		     XDefaultColormap(pxkDisplay, xscreen),
		     "light gray", &c1, &c2);

    values.foreground = c1.pixel;
    values.background = WhitePixel(pxkDisplay, xscreen);
    
    pxkLightgrayGC = XCreateGC(pxkDisplay, win, valuemask, &values);

    /* set drawing color to darkgray */
    XAllocNamedColor(pxkDisplay,
		     XDefaultColormap(pxkDisplay, xscreen),
		     "dim gray", &c1, &c2);

    values.foreground = c1.pixel;
    values.background = WhitePixel(pxkDisplay, xscreen);
    
    pxkDarkgrayGC = XCreateGC(pxkDisplay, win, valuemask, &values);

    views = [[NSMutableArray alloc] initWithCapacity:64];
    
    currentColor = [NSColor blackColor];
    
    return 0; /* success */
}

Window createXWindow(NSRect rect)
{
    XColor c1, c2;
    Window xWindow;
    XWMHints *wm_hints;
    XFontStruct *win_font;
    int xscreen = [(PXKScreen *)[NSScreen mainScreen] xScreen];
    
    if (!(wm_hints = XAllocWMHints())) {
	(void)fprintf(stderr, "Failure allocating memory\n");
        exit(0);
    }

    /*
     * Get the font
     */
    (void)load_font(&win_font);

#if 1
    XAllocNamedColor(pxkDisplay,
		     XDefaultColormap(pxkDisplay, xscreen),
		     "light gray", &c1, &c2);
#else
    XAllocNamedColor(pxkDisplay,
		     XDefaultColormap(pxkDisplay, xscreen),
		     "midnight blue", &c1, &c2);
#endif

    /*
     * Create a non-bordered, non-titled X window
     */

    rect.origin.x = 0;
    rect.origin.y = 0;
    rect.size.width = 600;
    rect.size.height = 900;

    xWindow = XCreateSimpleWindow(pxkDisplay, RootWindow(pxkDisplay,xscreen),
				  rect.origin.x,
				  rect.origin.y,
				  rect.size.width,
				  rect.size.height,
				  1,
				  BlackPixel(pxkDisplay,xscreen),
				  c1.pixel);

    /* Set the border width */
    XSetWindowBorderWidth(pxkDisplay, xWindow, 1);
    
    wm_hints->initial_state = NormalState;
    wm_hints->input = True;
    wm_hints->icon_pixmap = XCreateBitmapFromData(pxkDisplay,xWindow,
						  icon_bitmap_bits2, 
						  48,48);
    
    wm_hints->flags = StateHint | IconPixmapHint | InputHint;
    XSetWMHints(pxkDisplay, xWindow, wm_hints);
    
//    cursor = XC_top_left_arrow;

    XSelectInput(pxkDisplay, xWindow,
		 ExposureMask | KeyPressMask | KeyReleaseMask |
		 ButtonPressMask | ButtonReleaseMask | 
		 ButtonMotionMask | StructureNotifyMask |
		 PointerMotionMask | EnterWindowMask |
		 LeaveWindowMask | StructureNotifyMask | FocusChangeMask |
		 PropertyChangeMask | ColormapChangeMask | KeymapStateMask |
		 VisibilityChangeMask);

#if 1    
    (void)fprintf(stdout, "X windows count: %i\n", [views count]);
#endif

    return xWindow;
}

int numberForXWindow(Window win)
{
  NSArray *l = [NSApp windows];
  id e, o;

  e = [l objectEnumerator];
  o = [e nextObject];
  while (o)
    {
      if ([(PXKWindow *)o xWindow] == win)
	return [(NSWindow *)o windowNumber];
      o = [e nextObject];
    }

  NSLog(@"Could not find NSWindow for XWindow\n");
  return -1;
}

NSWindow *
nswindow_for_xwindow(Window win)
{
  NSArray *l = [NSApp windows];
  id e, o;

  // Is it even a valid window number
  if (win < 0) return nil;

  e = [l objectEnumerator];
  o = [e nextObject];
  while (o)
    {
      if ([(PXKWindow *)o xWindow] == win)
	return o;
      o = [e nextObject];
    }

  NSLog(@"Could not find NSWindow for XWindow\n");
  return nil;
}

Window xWindowWithId(int num)
{
  return -1;
}

int uniqueWindowId()
{
  return -1;
}

void
closeWindow(int windowNum)
{
    int index = indexOfViewNumber(windowNum);

    if (index < 0) {
	fprintf(stderr, "Error closing window: invalid window "
		"number: %i\n", windowNum);
    }
    XUnmapWindow(pxkDisplay, [[views objectAtIndex:index] xWindow]);
}

void setViewFrame(int viewNum, NSRect frameRect)
{
    int index = indexOfViewNumber(viewNum);
    PXKXWindow *rep = (PXKXWindow *)[views objectAtIndex:index];
    NSWindow *win = [(NSView *)[rep responder] window];
    NSRect winRect = [win frame];
    
    fprintf(stdout, "set frame to: %i %i %i %i\n",
	    PXK_MAX((int)frameRect.origin.x, 0),
	    PXK_MAX((int)winRect.size.height +
		    (int)frameRect.origin.y -
		    (int)frameRect.size.height, 0),	    
	    (int)frameRect.size.width,
	    (int)frameRect.size.height);

    XMoveResizeWindow(pxkDisplay,
		      [[views objectAtIndex:index] xWindow],
		      PXK_MAX((int)frameRect.origin.x, 0),	
		      PXK_MAX((int)winRect.size.height +
		      (int)frameRect.origin.y -
		      (int)frameRect.size.height, 0),
		      (int)frameRect.size.width,
		      (int)frameRect.size.height);    
}

void setViewFrameOrigin(int viewNum, NSPoint newOrigin)
{
    int index = indexOfViewNumber(viewNum);
    PXKXWindow *window;
    NSRect frameRect;

    if (index < 0) {
	fprintf(stderr, "setViewFrameOrigin() error: invalid view.\n");
	return;
    }

    window = [views objectAtIndex:index];

    frameRect = [(NSWindow *)[window responder] frame];
    
    XMoveWindow(pxkDisplay, [window xWindow], newOrigin.x,
		pxkDisplayHeight - newOrigin.y - frameRect.size.height);
}

void setViewFrameRotation(int viewNum, float angle)
{
    /* Not supported by this incarnation of the drawing engine. */
}

void setViewFrameSize(int viewNum, NSSize newSize)
{
    int index = indexOfViewNumber(viewNum);
    PXKXWindow *window;
    NSRect rect;

    if (index < 0) {
	fprintf(stderr, "setViewFrameSize() error: invalid view.\n");
	return;
    }   
    
    window = [views objectAtIndex:index];

    rect = [(NSWindow *)[window responder] frame];
    
    XMoveResizeWindow(pxkDisplay,
		      [window xWindow],
		      rect.origin.x,

		      pxkDisplayHeight -
		      rect.origin.y -
		      rect.size.height,

		      newSize.width,
		      newSize.height);   
}

void setWindowFrame(int windowNum, NSRect frameRect)
{
    int index = indexOfViewNumber(windowNum);
    
    fprintf(stdout, "set frame to: %i %i %i %i\n",
	    PXK_MAX((int)frameRect.origin.x, 0),
	    PXK_MAX((int)pxkDisplayHeight -
		    (int)frameRect.origin.y -
		    (int)frameRect.size.height, 0),	    
	    (int)frameRect.size.width,
	    (int)frameRect.size.height);

    XMoveResizeWindow(pxkDisplay,
		      [[views objectAtIndex:index] xWindow],
		      PXK_MAX((int)frameRect.origin.x, 0),	
		      PXK_MAX((int)pxkDisplayHeight -
		      (int)frameRect.origin.y -
		      (int)frameRect.size.height, 0),
		      (int)frameRect.size.width,
		      (int)frameRect.size.height);    
}

void setWindowFrameOrigin(int windowNum, NSPoint newOrigin)
{
    setViewFrameOrigin(windowNum, newOrigin);
}

void setWindowFrameSize(int windowNum, NSSize newSize)
{
    setViewFrameSize(windowNum, newSize);
}

/* Utility functions not part of OpenStep */

void setCurrentColor(NSColor *aColor)
{
    currentColor = aColor;
}

/* Functions to be called by other elements of the drawing engine */

int indexOfViewNumber(int viewNum)
{
    int count = [views count];

    while(count > 0) {
	if ([[views objectAtIndex:count-1] windowNumber] == viewNum) {
	    //fprintf(stderr,"index: %i of view number: %i\n",count-1,viewNum);
	    return count-1;
	}
	count--;
    }
    return -1; /* not found */	    
}

int indexOfXWindowRepresentingAView(Window xWindow)
{
    int count = [views count];

    while(count > 0) {
	if ([[views objectAtIndex:count-1] xWindow] == xWindow) {
	    fprintf(stderr, "indexOfXWindowRep.... : %i\n", count-1);
	    return count-1;
	}
	count--;
    }
    return -1; /* not found */	    
}

int indexOfXWindowRepresentingAWindow(Window xWindow)
{
    return indexOfXWindowRepresentingAView(xWindow);
}

/* These are called from NSApplication */

void miniaturizeAll(id sender)
{
    
    
}

void preventWindowOrdering(void)
{
    
}

void updateWindows(void)
{
}

/* Application Kit Functions */

/* Rectangle Drawing Functions */

// Oops, DPS stuff still needs to be cleaned up - scott
#if 0
void NSRectFill(NSRect aRect)            /* Fills rect using current color   */
{
    pxkFillRect(aRect, currentColor);
}

void NSRectFillList(const NSRect *rects, int count) 
{
    int i;
    
    for (i=0; i<count; i++) {
	pxkFillRect(rects[i], currentColor);
    }
}

/*
 * NSRectFillWithGrays() Fills each rectangle in the array 'rects'
 * with the gray whose value is stored at the corresponding location
 * in the array 'grays'.  Both arrays must be count elements long.
 * Avoid overlapping rectangles, because the drawing order can't be
 * guaranteed.
 */

void NSRectFillListWithGrays(const NSRect *rects,const float *grays,int count) 
{
}
#endif


/* Draw a line (private function) */

void
pxkDrawLine(NSPoint a, NSPoint b, NSColor *color)
{
    NSView *focusView = [NSView focusView];
    int windowId;

    if (focusView != nil) {
	windowId = [(PXKView *)focusView viewNum];
	
	/* Let's cheat a little in order to speed up things */

	if (color == [NSColor blackColor]) {
	    //puts("black color");
	    //fprintf(stdout, "windowId: %d\n", windowId);
	    XDrawLine(pxkDisplay,
		      xWindowWithId(windowId),
		      pxkBlackGC,
		      a.x,a.y,b.x,b.y);
	} else if (color == [NSColor whiteColor]) {
	    XDrawLine(pxkDisplay,
		      xWindowWithId(windowId),
		      pxkWhiteGC,
		      a.x,a.y,b.x,b.y);
	} else if (color == [NSColor darkGrayColor]) {
	    XDrawLine(pxkDisplay,
		      xWindowWithId(windowId),
		      pxkDarkgrayGC,
		      a.x,a.y,b.x,b.y);
	} else if (color == [NSColor lightGrayColor]) {
	    XDrawLine(pxkDisplay,
		      xWindowWithId(windowId),
		      pxkLightgrayGC,
		      a.x,a.y,b.x,b.y);
	}
    } else {
	puts("No view in focus!!!");
    }
}

/*
 * Draw a line that's defined as an NSRect instead of 2 points
 */

void
pxkDrawLineRect(NSRect line, NSColor *color)
{
    NSPoint a = line.origin;
    NSPoint b;

    /* Do not display lines where width or height < 0 */
    
    if ((line.size.width >= 0) && (line.size.height >= 0)) {
	b.x = line.origin.x + line.size.width;
	b.y = line.origin.y + line.size.height;    
	pxkDrawLine(a, b, color);
    }
}

void
pxkFillRect(NSRect rect, NSColor *color)
{
    NSView *focusView = [NSView focusView];
    int windowId;

    if (focusView != nil) {
	windowId = [(PXKView *)focusView viewNum];
	
	/* Let's cheat a little in order to speed up things */

	if (color == [NSColor blackColor]) {
	    XFillRectangle(pxkDisplay,
			   xWindowWithId(windowId),
			   pxkBlackGC,
			   rect.origin.x,
			   rect.origin.y,
			   rect.size.width,
			   rect.size.height);
	} else if (color == [NSColor whiteColor]) {
	    XFillRectangle(pxkDisplay,
			   xWindowWithId(windowId),
			   pxkWhiteGC,
			   rect.origin.x,
			   rect.origin.y,
			   rect.size.width,
			   rect.size.height);
	} else if (color == [NSColor darkGrayColor]) {
	    XFillRectangle(pxkDisplay,
			   xWindowWithId(windowId),
			   pxkDarkgrayGC,
			   rect.origin.x,
			   rect.origin.y,
			   rect.size.width,
			   rect.size.height);
	} else if (color == [NSColor lightGrayColor]) {
	    XFillRectangle(pxkDisplay,
			   xWindowWithId(windowId),
			   pxkLightgrayGC,
			   rect.origin.x,
			   rect.origin.y,
			   rect.size.width,
			   rect.size.height);
	}
    } else {
	pxkDebugMsg("No view in focus!!!");
    }
}


/* Private functions, not part of the OpenStep specification */
NSPoint intersectionPoint(NSRect lineA, NSRect lineB)
{
    NSPoint aPoint;
    float r, s;
    float XA = lineA.origin.x;
    float XB = lineA.origin.x + lineA.size.width;
    float XC = lineB.origin.x;
    float XD = lineB.origin.x + lineB.size.width;
    float YA = lineA.origin.y;
    float YB = lineA.origin.y + lineA.size.height;
    float YC = lineB.origin.y;
    float YD = lineB.origin.y + lineB.size.height;
    float denominator = (XB-XA)*(YD-YC)-(YB-YA)*(XD-XC);
    
    /*
      The following code taken from comp.graphics.algorithms FAQ.
      
      This problem can be extremely easy or extremely difficult
      depends on your applications. If all you want is the
      intersection point, the following should work:
      
      Let A,B,C,D be 2-space position vectors. Then the directed
      line segments AB and CD are given by:
	  
	  AB=A+r(B-A), r in [0,1]
	  CD=C+s(D-C), s in [0,1]
		  
          If AB and CD intersect, then

	  A+r(B-A)=C+s(D-C)

          or

	  XA+r(XB-XA)=XC+s(XD-XC)
	  YA+r(YB-YA)=YC+s(YD-YC)  for some r,s in [0,1]
	  
          Solving the above for r and s yields
 
	       (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
          r = -----------------------------  (eqn 1)
	       (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
	  
	       (YA-YC)(XB-XA)-(XA-XC)(YB-YA)
	   s = -----------------------------  (eqn 2)
	       (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
	       
	   */
    
    if ((denominator < 0.00000001) && (denominator > -0.00000001)) {
	fprintf(stderr, "in function intersect(), lines are parallel.\n");
	aPoint.x = -1;
	aPoint.y = -1; /* x and y are always positive in this toolkit */
    }
    
    r = ((YA-YC)*(XD-XC)-(XA-XC)*(YD-YC)) / denominator;
    s = ((YA-YC)*(XB-XA)-(XA-XC)*(YB-YA)) / denominator;
    
         /*
          Let I be the position vector of the intersection point, then

	  I=A+r(B-A)

          or

	  XI=XA+r(XB-XA)
	  YI=YA+r(YB-YA)    

	  */
	
    aPoint.x = XA+r*(XB-XA);
    aPoint.y = YA+r*(YB-YA);
    
    /*
	  By examining the values of r and s, you can also determine
	  some other limiting conditions:
	  
	  If 0 <= r <= 1 and 0 <= s <= 1, intersection exists
	  r < 0 or r>1 or s < 0 or s>1 line segments do not intersect
	  
	  If the denominator in eqn 1 is zero, AB and CD are parallel
          If the numerator in eqn 1 is also zero, AB and CD are
          coincident

          If the intersection point of the 2 lines are needed (lines in
          this context mean infinite lines) regardless whether the two
          line segments intersect, then

          If r > 1, I is located on extension of AB
          If r < 0, I is located on extension of BA
          If s > 1, I is located on extension of CD
          If s < 0, I is located on extension of DC

          Also note that the denominators of equations 1 and 2 are
          identical.

          References:
	  
          [O'Rourke] pp. 249-51
          [Gems3] pp. 199-202 "Faster Line Segment Intersection,"
	  */

    return aPoint;
}

float dist2D(NSPoint a, NSPoint b)
{
    return (a.x-b.x)*(a.x - b.x) / ((a.y-b.y)*(a.y-b.y));
}

NSRect clipLineToRect(NSRect aLine, NSRect aRect)
{
    NSRect resultLine = aLine;
    NSRect clipLine;
    NSPoint aPoint;
    float XA, XB, YA, YB;
    
    XA = aLine.origin.x;
    XB = aLine.origin.x + aLine.size.width;
    YA = aLine.origin.y;
    YB = aLine.origin.y + aLine.size.height;

    /*
     * Set height = width = -1  for lines that are totally
     * outside of the clipping rectangle.
     */

    if (((XA < aRect.origin.x) && (XB < aRect.origin.x)) ||
	((XA > aRect.origin.x + aRect.size.width) &&
	 (XB > aRect.origin.x + aRect.size.width)) ||
	((YA < aRect.origin.y) && (YB < aRect.origin.y)) ||
	((YA > aRect.origin.x + aRect.size.width) &&
	 (YB > aRect.origin.x + aRect.size.width)))
    {
	resultLine.size.width = resultLine.size.height = -1;
	return resultLine;
    }
    
    /* clip left */
    
    if ((XA <= aRect.origin.x) && (XB >= aRect.origin.x)) {
	
	pxkDebugMsg("clip left");
	
	clipLine = aRect;
	clipLine.size.width = 0.0;
	
	aPoint = intersectionPoint(aLine, clipLine);
    
	resultLine.origin.x = aPoint.x;
	resultLine.origin.y = aPoint.y;
	resultLine.size.width = XB - aPoint.x;
	resultLine.size.height = YB - aPoint.y;
    }

    /* clip right */
    
    if ((XA <= aRect.origin.x + aRect.size.width) &&
	(XB >= aRect.origin.x + aRect.size.width))
    {
	pxkDebugMsg("clip right");
	
	clipLine = aRect;
	clipLine.origin.x += clipLine.size.width;
	clipLine.size.width = 0.0;
	
	aPoint = intersectionPoint(aLine, clipLine);
    
	resultLine.origin.x = aPoint.x;
	resultLine.origin.y = aPoint.y;
	resultLine.size.width = XB - aPoint.x;
	resultLine.size.height = YB - aPoint.y;
    }

    /* clip bottom */
    
    if ((YA <= aRect.origin.y + aRect.size.height) &&
	(YB >= aRect.origin.y + aRect.size.height))
    {
	pxkDebugMsg("clip bottom");
	
	clipLine = aRect;
	clipLine.size.height = 0.0;
	
	aPoint = intersectionPoint(aLine, clipLine);
    
	resultLine.origin.x = aPoint.x;
	resultLine.origin.y = aPoint.y;
	resultLine.size.width = XB - aPoint.x;
	resultLine.size.height = YB - aPoint.y;
    }

    /* clip top */
    
    if ((YA <= aRect.origin.y) && (YB >= aRect.origin.y)) {
	pxkDebugMsg("clip top");	
	
	clipLine = aRect;
	clipLine.origin.x += clipLine.size.height;
	clipLine.size.height = 0.0;
	
	aPoint = intersectionPoint(aLine, clipLine);
    
	resultLine.origin.x = aPoint.x;
	resultLine.origin.y = aPoint.y;
	resultLine.size.width = XB - aPoint.x;
	resultLine.size.height = YB - aPoint.y;
    }

    return resultLine;
}

#if 0

/* Draw a Bordered Rectangle */

void NSDrawButton(NSRect aRect, NSRect clipRect)     /* Bordered ltgray rect */
{
    NSRect line;
    
    /* Draw the top white line */    
    line = aRect;
    line.size.height = 0;
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor whiteColor]);
    
    /* Draw the left white line */
    line = aRect;
    line.size.width = 0;
    line.size.height -= 1; /* line doesn't draw down to the last pixel */
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor whiteColor]);    
    
    /* Draw the bottom black line */
    line = aRect;
    line.origin.y += line.size.height;
    line.size.height = 0;    
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor blackColor]);

    /* Draw the bottom darkgray line above the black line */
    line.origin.y--;
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor darkGrayColor]);

    /* Draw the right black line */
    line = aRect;
    line.origin.x += line.size.width;
    line.size.width = 0;
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor blackColor]);

    /* Draw the right darkgray line */
    line.origin.x--;
    line.origin.y++;
    line.size.height -= 2.0; /* line doesn't draw down to the last pixel */
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor darkGrayColor]);  
}

void NSDrawGrayBezel(NSRect aRect, NSRect clipRect)  /* pushed-in button     */
{ /* Like the border of a TextField? */
    NSRect line;
    
    /* Draw the top darkgray line */ 
    line = aRect;
    line.size.height = 0;
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor darkGrayColor]);
    
    /* Draw the top darkgray line below the darkgray line */    
    line.origin.y++;
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor darkGrayColor]);
    
    /* Draw the left darkgray line */
    line = aRect;
    line.size.width = 0;
    line.size.height--;
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor darkGrayColor]);

    /* Draw the left darkgray line, besides the vertical darkgray line */
    line.origin.x++;
    line.size.height--;
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor darkGrayColor]);    
    
    /* Draw the bottom white line */
    line = aRect;
    line.origin.y += line.size.height;
    line.size.height = 0;    
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor whiteColor]);

    /* Draw the bottom lightgray line above the white line */
    line.origin.x++;
    line.size.width--;
    line.origin.y--;
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor lightGrayColor]);

    /* Draw the right white line */
    line = aRect;
    line.origin.x += line.size.width;
    line.size.width = 0;
    line.origin.y++;
    line.size.height--;
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor whiteColor]);

    /* Draw the right lightgray line */
    line.origin.x--;
    line.origin.y++;
    line.size.height -= 2.0; /* line doesn't draw down to the last pixel */
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor lightGrayColor]);
}

void NSDrawGroove(NSRect aRect, NSRect clipRect)     /* like a Box           */
{
    NSRect line;
    
    /* Draw the top darkgray line */    
    line = aRect;
    line.size.height = 0;
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor darkGrayColor]);
    
    /* Draw the top white line below the darkgray line */    
    line.origin.y++;
    line.origin.x++;
    line.size.width--;
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor whiteColor]);
    
    /* Draw the left darkgray line */
    line = aRect;
    line.size.width = 0;
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor darkGrayColor]);

    /* Draw the left white line, besides the vertical darkgray line */
    line.origin.x++;
    line.origin.y++;
    line.size.height--;
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor whiteColor]);    
    
    /* Draw the bottom white line */
    line = aRect;
    line.origin.x++;
    line.size.width--;
    line.origin.y += line.size.height;
    line.size.height = 0;    
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor whiteColor]);

    /* Draw the bottom darkgray line above the white line */
    line.origin.x++;
    line.size.width--;
    line.origin.y--;
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor darkGrayColor]);

    /* Draw the right white line */
    line = aRect;
    line.origin.x += line.size.width;
    line.size.width = 0;
    line.origin.y++;
    line.size.height--;
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor whiteColor]);

    /* Draw the right darkgray line */
    line.origin.x--;
    line.origin.y++;
    line.size.height -= 2.0; /* line doesn't draw down to the last pixel */
    pxkDrawLineRect(clipLineToRect(line, clipRect), [NSColor darkGrayColor]);  
}

#if 0
void NSDrawTiledRects(NSRect boundsRect,
		      NSRect clipRect,
		      const NSRectEdge *sides,
		      const float *grays,
		      int count) 
{
}
#endif

void NSDrawWhiteBezel(NSRect aRect, NSRect clipRect)  /* like a TextField    */
{
}

void NSFrameRect(NSRect aRect)  /* Draws a frame of width 1.0 use curr color */
{
    NSPoint a, b;
    
    a = aRect.origin;
    b.x = aRect.origin.x + aRect.size.width;
    b.y = aRect.origin.y;
    pxkDrawLine(a, b, currentColor);

    a.x = b.x;
    a.y += aRect.origin.y + aRect.size.height;
    pxkDrawLine(a, b, currentColor);

    b.x = aRect.origin.x;
    b.y = a.y;
    pxkDrawLine(a, b, currentColor);

    pxkDrawLine(aRect.origin, b, currentColor);
}

void NSFrameRectWithWidth(NSRect aRect, float frameWidth) 
{
}
#endif

// More DPS garbage
#if 1
void MB__rectfill(id self, float X, float Y, float WIDTH, float HEIGHT)
{}
void MB__set_color(id self, NSColor *c)
{}
void MB__rectstroke(id self, float X, float Y, float WIDTH, float HEIGHT)
{}
#endif

Display *
xDisplay(void)
{
    return pxkDisplay;
}


