/*
 * File:      wx_dc.cc
 * Purpose:     Device context implementation
 * Author:      Julian Smart
 * Created:     1993
 * Updated:	August 1994
 * RCS_ID:      $Id: wx_dc.cc,v 1.4 1994/08/14 21:28:43 edz Exp $
 * Copyright:   (c) 1993, AIAI, University of Edinburgh
 */

static const char sccsid[] = "@(#)wx_dc.cc	1.2 5/9/94";

#ifdef __GNUG__
#pragma implementation
#pragma implementation "wx_dc.h"
#pragma implementation "wx_dccan.h"
#pragma implementation "wx_dcpan.h"
#pragma implementation "wx_dcmem.h"
#endif

#include <iostream.h>
#include <fstream.h>
#include <math.h>
#ifndef M_PI
/*steve: in some math libs this is not defined! */
#define M_PI 3.14159265
#endif
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include "common.h"
#include "wx_frame.h"
#include "wx_dc.h"
#include "wx_dccan.h"
#include "wx_dcpan.h"
#include "wx_dcmem.h"
#include "wx_dcps.h"
#include "wx_utils.h"
#include "wx_canvs.h"
#include "wx_panel.h"
#include "wx_main.h"
#include "wx_privt.h"

#include "bdiag.xbm"
#include "fdiag.xbm"
#include "cdiag.xbm"
#include "horiz.xbm"
#include "verti.xbm"
#include "cross.xbm"

static Pixmap bdiag, cdiag, fdiag, cross, horiz, verti;

// Declarations local to this file
#define YSCALE(y) (yorigin - (y))
#define     wx_round(a)    (int)((a)+.5)

// Matthew Flatt's (I think)
#ifdef MACH_TRUNCS_NEG_UP
static inline int ROUND(float f)
{
  if (f > 0) 
    return (int)(f + 0.5); 
  else {
    int v = (int)f;
    if (v - f > 0.5)
      return v - 1;
    else
      return v;
  }
}
#else
#define ROUND(x) (int)((x) + 0.5)
#endif

// Added by Patrick...
// Needs further explanation before it's used!
#if PIXEL0_DISABLE
Status 
YAllocColor (Display * dpy, Colormap cmap, XColor * color)
{
  // Allocate a Color, but avoid to get the pixel #0
  // If such pixel is returned, return a R/W cell instead.
  // This is necessary to have workable wxXOR, wxOR,...
  // because anything XOR 0 = anything,
  //         anything  OR 0 = anything, so no visual effects!
  // Please note that there is also a potential pb whith pixel 255 and
  // wxAND -- but if we allocate pixel 255 as ReadOnly, there is probably
  // no more R/W cells.

  //wxDebugMsg("YAllocColor %d,%d,%d\n",color->red,color->green,color->blue) ;
  Status result = XAllocColor (dpy, cmap, color);

  if (result == 0)
    return (0);
  if (color->pixel == 0)
    {
      // Ooops... we don't want THIS pixel!!!
      result = XAllocColorCells (dpy, cmap, False, NULL, 0, &color->pixel, 1);
      // No R/W. We must deal with pixel 0. Aaaaarghhh!
      if (result == 0)
	return XAllocColor (dpy, cmap, color);
      XStoreColor (dpy, cmap, color);
    }
  return (result);
}
#else
#define YAllocColor XAllocColor
#endif


extern Colormap wxMainColormap;

IMPLEMENT_ABSTRACT_CLASS(wxDC, wxWindow)
IMPLEMENT_DYNAMIC_CLASS(wxCanvasDC, wxDC)

// Default constructor
wxCanvasDC::wxCanvasDC (void)
{
  __type = wxTYPE_DC_CANVAS;
  selected_pixmap = NULL;
  canvas = NULL;
  pixmap = 0;
  pixmapWidth = 0;
  pixmapHeight = 0;
  display = NULL;
  clipping = FALSE;

  current_reg = NULL;
  user_reg = NULL;
  onpaint_reg = NULL;

  device = wxDEVICE_CANVAS;
  font = NULL;

  min_x = 0;
  min_y = 0;
  max_x = 0;
  max_y = 0;

  logical_origin_x = 0;
  logical_origin_y = 0;

  device_origin_x = 0;
  device_origin_y = 0;

  logical_scale_x = 1.0;
  logical_scale_y = 1.0;

  user_scale_x = 1.0;
  user_scale_y = 1.0;

  mapping_mode = MM_TEXT;

  title = NULL;

  gc = NULL;
#ifdef wx_motif
  gcBacking = NULL;
#endif

  background_pixel = 0;
  ok = TRUE;
  current_pen_width = -1;
  current_pen_join = -1;
  current_pen_cap = -1;
  current_pen_nb_dash = -1;
  current_pen_dash = NULL;
  current_stipple = NULL;
  current_style = -1;
  current_fill = -1;

  current_logical_function = -1;

  current_pen = NULL;
  current_brush = NULL;
  current_background_brush = wxWHITE_BRUSH;
  current_text_foreground = *wxBLACK;
  current_text_background = *wxWHITE;
  current_bk_mode = wxTRANSPARENT;
  Colour = wxColourDisplay ();
}


wxCanvasDC:: wxCanvasDC (wxCanvas * the_canvas):wxbCanvasDC (the_canvas)
{
  __type = wxTYPE_DC_CANVAS;
  canvas = the_canvas;
  clipping = FALSE;
  display = canvas->GetXDisplay();
  selected_pixmap = NULL;
  pixmap = canvas->GetXWindow();
  XSetWindowColormap (display, pixmap, wxMainColormap);

  pixmapWidth = 0;
  pixmapHeight = 0;

  current_reg = NULL;
  user_reg = NULL;
  onpaint_reg = NULL;

  min_x = 0;
  min_y = 0;
  max_x = 0;
  max_y = 0;

  device = wxDEVICE_CANVAS;
  font = NULL;

  logical_origin_x = 0;
  logical_origin_y = 0;

  device_origin_x = 0;
  device_origin_y = 0;

  logical_scale_x = 1.0;
  logical_scale_y = 1.0;

  user_scale_x = 1.0;
  user_scale_y = 1.0;

  mapping_mode = MM_TEXT;

  title = NULL;

  XGCValues gcvalues;
  gcvalues.foreground = BlackPixel (display, DefaultScreen (display));
  gcvalues.background = WhitePixel (display, DefaultScreen (display));
  gcvalues.graphics_exposures = False;
  gcvalues.line_width = 1;
  gc = XCreateGC (display, RootWindow (display, DefaultScreen (display)),
	    GCForeground | GCBackground | GCGraphicsExposures | GCLineWidth,
		  &gcvalues);
#ifdef wx_motif
  gcBacking = XCreateGC (display, RootWindow (display,
					      DefaultScreen (display)),
	    GCForeground | GCBackground | GCGraphicsExposures | GCLineWidth,
			 &gcvalues);
#endif

  background_pixel = (int) gcvalues.background;
  ok = TRUE;
  current_pen_width = -1;
  current_pen_join = -1;
  current_pen_cap = -1;
  current_pen_nb_dash = -1;
  current_pen_dash = NULL;
  current_logical_function = -1;
  current_stipple = NULL;
  current_style = -1;
  current_fill = -1;

  current_pen = NULL;
  current_brush = NULL;
  current_background_brush = wxWHITE_BRUSH;
  current_text_foreground = *wxBLACK;
  current_text_background = *wxWHITE;
  current_bk_mode = wxTRANSPARENT;
  Colour = wxColourDisplay ();
  SetBrush (wxWHITE_BRUSH);
  SetPen (wxBLACK_PEN);
}

wxCanvasDC::~wxCanvasDC (void)
{
  if (gc)
    XFreeGC (display, gc);
  gc = NULL;
#ifdef wx_motif
  if (gcBacking)
    XFreeGC (display, gcBacking);
  gcBacking = NULL;
#endif
}

void wxCanvasDC:: SetCanvasClipping (void)
{
  if (current_reg)
    XDestroyRegion (current_reg);

  if (user_reg || onpaint_reg)
    current_reg = XCreateRegion ();
  else
    current_reg = NULL;

  if (onpaint_reg && user_reg)
    XIntersectRegion (onpaint_reg, user_reg, current_reg);
  else if (user_reg)
    XIntersectRegion (user_reg, user_reg, current_reg);
  else if (onpaint_reg)
    XIntersectRegion (onpaint_reg, onpaint_reg, current_reg);

  if (current_reg)
    {
      XSetRegion (display, gc, current_reg);
#ifdef wx_motif
// NO, see SetClippingRegion
//      if (canvas && canvas->is_retained)
//	XSetRegion (display, gcBacking, current_reg);
#endif
    }
  else
    {
      XSetClipMask (display, gc, None);
#ifdef wx_motif
//      if (canvas && canvas->is_retained)
//	XSetClipMask (display, gcBacking, None);
#endif
    }

}

void wxCanvasDC:: GetClippingBox (float *x, float *y, float *w, float *h)
{
  if (current_reg)
    {
      XRectangle r;
      XClipBox (current_reg, &r);
      *x = XDEV2LOG (r.x);
      *y = YDEV2LOG (r.y);
      *w = XDEV2LOGREL (r.width);
      *h = YDEV2LOGREL (r.height);
    }
  else
    *x = *y = *w = *h = 0;
}

void wxCanvasDC:: SetClippingRegion (float cx, float cy, float cw, float ch)
{
/****
old code, not using optimized Regions

        XRectangle rects[1];

        rects[0].x = XLOG2DEV(cx); rects[0].y = YLOG2DEV(cy);
        rects[0].width = XLOG2DEVREL(cw); rects[0].height = YLOG2DEVREL(ch);
        XSetClipRectangles(display, gc, 0, 0, rects, 1, Unsorted);
#ifdef wx_motif
        if (canvas && canvas->is_retained)
	{
          rects[0].x = XLOG2DEV_2(cx); rects[0].y = YLOG2DEV_2(cy);
          rects[0].width = XLOG2DEVREL(cw); rects[0].height = YLOG2DEVREL(ch);
          XSetClipRectangles(display, gcBacking, 0, 0, rects, 1, Unsorted);
	}
#endif
****/

  if (user_reg)
    XDestroyRegion (user_reg);
  user_reg = XCreateRegion ();
  XRectangle r;
  r.x = XLOG2DEV (cx);
  r.y = YLOG2DEV (cy);
  r.width = XLOG2DEVREL (cw);
  r.height = YLOG2DEVREL (ch);
  XUnionRectWithRegion (&r, user_reg, user_reg);
  SetCanvasClipping ();

  // Needs to work differently for Pixmap: without this,
  // there's a nasty display bug. 8/12/94
#ifdef wx_motif
  if (canvas && canvas->is_retained)
  {
    XRectangle rects[1];
    rects[0].x = XLOG2DEV_2(cx); rects[0].y = YLOG2DEV_2(cy);
    rects[0].width = XLOG2DEVREL(cw); rects[0].height = YLOG2DEVREL(ch);
    XSetClipRectangles(display, gcBacking, 0, 0, rects, 1, Unsorted);
  }
#endif
}

void wxCanvasDC:: DestroyClippingRegion (void)
{
/***
old code, not using optimized Regions

        XGCValues gc_val;
        gc_val.clip_mask = None;
        XChangeGC(display, gc, GCClipMask, &gc_val);
#ifdef wx_motif
        if (canvas && canvas->is_retained)
	{
          XChangeGC(display, gcBacking, GCClipMask, &gc_val);
	}
#endif
#ifdef wx_xview
        if (canvas && canvas->xrects)
          XSetClipRectangles(display, gc, 0, 0, canvas->xrects->rect_array,
                           canvas->xrects->count, Unsorted);
#endif
***/

  if (user_reg)
    XDestroyRegion (user_reg);
  user_reg = NULL;
  SetCanvasClipping ();

  // Bug fix for Motif backing pixmap, see comment above.
#ifdef wx_motif
  XGCValues gc_val;
  gc_val.clip_mask = None;
  if (canvas && canvas->is_retained)
    XChangeGC(display, gcBacking, GCClipMask, &gc_val);
#endif
}

void wxCanvasDC:: Clear (void)
{
/*
   #ifdef wx_xview
   // If we're not in the middle of a paint event...
   if (!canvas->xrects || !(canvas && canvas->is_retained))
   XClearWindow(display, pixmap);
   #endif
 */
  int w, h;
  if (canvas)
    {
      canvas->GetVirtualSize (&w, &h);

#ifdef wx_motif
      if (canvas->hScroll)
	w = canvas->hExtent;
      if (canvas->vScroll)
	h = canvas->vExtent;

      if (canvas && canvas->is_retained)
	{
	  w = canvas->pixmapWidth;
	  h = canvas->pixmapHeight;
	}
#endif
    }
  else
    {
      w = pixmapWidth;
      h = pixmapHeight;
    }

  autoSetting = TRUE;		// must be reset

  SetBrush (current_background_brush);
  XFillRectangle (display, pixmap, gc, 0, 0, w, h);
#ifdef wx_motif
  if (canvas && canvas->is_retained)
    XFillRectangle (display, canvas->backingPixmap, gcBacking, 0, 0, w, h);
#endif
}

void wxCanvasDC:: CrossHair (int x, int y)
{
  if (current_pen && autoSetting)
    SetPen (current_pen);
  int xx = XLOG2DEV (x);
  int yy = YLOG2DEV (y);
  int ww, hh;
  wxDisplaySize (&ww, &hh);
  XDrawLine (display, pixmap, gc, 0, yy,
	     ww, yy);
  XDrawLine (display, pixmap, gc, xx, 0,
	     xx, hh);
#ifdef wx_motif
  if (canvas && canvas->is_retained)
    {
      xx = XLOG2DEV_2 (x);
      yy = YLOG2DEV_2 (y);
      XDrawLine (display, canvas->backingPixmap, gcBacking,
		 0, yy,
		 ww, yy);
      XDrawLine (display, canvas->backingPixmap, gcBacking,
		 xx, 0,
		 xx, hh);
    }
#endif
}

void wxCanvasDC:: FloodFill (float x, float y, wxColour * col, int style)
{
}

Bool wxCanvasDC:: GetPixel (float x, float y, wxColour * col)
{
  return FALSE;
}

void wxCanvasDC:: IntDrawLine (int x1, int y1, int x2, int y2)
{
  if (current_pen && autoSetting)
    SetPen (current_pen);
  XDrawLine (display, pixmap, gc, XLOG2DEV (x1), YLOG2DEV (y1),
	     XLOG2DEV (x2), YLOG2DEV (y2));
#ifdef wx_motif
  if (canvas && canvas->is_retained)
    XDrawLine (display, canvas->backingPixmap, gcBacking, XLOG2DEV_2 (x1), YLOG2DEV_2 (y1),
	       XLOG2DEV_2 (x2), YLOG2DEV_2 (y2));
#endif
}

void wxCanvasDC:: DrawLine (float x1, float y1, float x2, float y2)
{
  if (current_pen && autoSetting)
    SetPen (current_pen);
  XDrawLine (display, pixmap, gc, XLOG2DEV (x1), YLOG2DEV (y1),
	     XLOG2DEV (x2), YLOG2DEV (y2));
#ifdef wx_motif
  if (canvas && canvas->is_retained)
    XDrawLine (display, canvas->backingPixmap, gcBacking, XLOG2DEV_2 (x1), YLOG2DEV_2 (y1),
	       XLOG2DEV_2 (x2), YLOG2DEV_2 (y2));
#endif
  CalcBoundingBox (x1, y1);
  CalcBoundingBox (x2, y2);
}

void wxCanvasDC:: DrawArc (float x1, float y1, float x2, float y2, float xc, float yc)
{
  int xx1 = XLOG2DEV (x1);
  int yy1 = YLOG2DEV (y1);
  int xx2 = XLOG2DEV (x2);
  int yy2 = YLOG2DEV (y2);
  int xxc = XLOG2DEV (xc);
  int yyc = YLOG2DEV (yc);
  int xxc_2 = XLOG2DEV_2 (xc);
  int yyc_2 = YLOG2DEV_2 (yc);

  double dx = xx1 - xxc;
  double dy = yy1 - yyc;
  double radius = sqrt (dx * dx + dy * dy);
  int r = (int) radius;

  double radius1, radius2;

  if (xx1 == xx2 && yy1 == yy2)
    {
      radius1 = 0.0;
      radius2 = 360.0;
    }
  else if (radius == 0.0)
    radius1 = radius2 = 0.0;
  else
    {
      if (xx1 - xxc == 0)
	if (yy1 - yyc < 0)
	  radius1 = 90.0;
	else
	  radius1 = -90.0;
      else
	radius1 = -atan2 ((double) (yy1 - yyc), (double) (xx1 - xxc)) * 360.0 / (2 * M_PI);

      if (xx2 - xxc == 0)
	if (yy2 - yyc < 0)
	  radius2 = 90.0;
	else
	  radius2 = -90.0;
      else
	radius2 = -atan2 ((double) (yy2 - yyc), (double) (xx2 - xxc)) * 360.0 / (2 * M_PI);
    }
  radius1 *= 64.0;
  radius2 *= 64.0;
  int alpha1 = (int) radius1;
  int alpha2 = (int) (radius2 - radius1);
  while (alpha2 <= 0)
    alpha2 += 360 * 64;
  while (alpha2 > 360 * 64)
    alpha2 -= 360 * 64;

  if (current_brush && current_brush->GetStyle () != wxTRANSPARENT)
    {
      autoSetting = TRUE;	// must be reset

      SetBrush (current_brush);
      XFillArc (display, pixmap, gc,
		xxc - r, yyc - r, 2 * r, 2 * r, alpha1, alpha2);
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	XFillArc (display, canvas->backingPixmap, gcBacking,
		  xxc_2 - r, yyc_2 - r, 2 * r, 2 * r, alpha1, alpha2);
#endif
    }

  if (current_pen && current_pen->GetStyle () != wxTRANSPARENT)
    {
      if (autoSetting)
	SetPen (current_pen);
      XDrawArc (display, pixmap, gc,
		xxc - r, yyc - r, 2 * r, 2 * r, alpha1, alpha2);
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	XDrawArc (display, canvas->backingPixmap, gcBacking,
		  xxc_2 - r, yyc_2 - r, 2 * r, 2 * r, alpha1, alpha2);
#endif
    }
  CalcBoundingBox (x1, y1);
  CalcBoundingBox (x2, y2);
}

void wxCanvasDC:: DrawPoint (float x, float y)
{
  if (current_pen && autoSetting)
    SetPen (current_pen);

  XDrawPoint (display, pixmap, gc, XLOG2DEV (x), YLOG2DEV (y));
#ifdef wx_motif
  if (canvas && canvas->is_retained)
    XDrawPoint (display, canvas->backingPixmap, gcBacking, XLOG2DEV_2 (x), YLOG2DEV_2 (y));
#endif
  CalcBoundingBox (x, y);
}

void wxCanvasDC:: DrawPolygon (int n, wxPoint points[], float xoffset, float yoffset, int fillStyle)
{
  XPoint *xpoints1 = new XPoint[n + 1];
  XPoint *xpoints2 = new XPoint[n + 1];
  int i;
  for (i = 0; i < n; i++)
    {
      xpoints1[i].x = XLOG2DEV (points[i].x + xoffset);
      xpoints1[i].y = YLOG2DEV (points[i].y + yoffset);
      xpoints2[i].x = XLOG2DEV_2 (points[i].x + xoffset);
      xpoints2[i].y = YLOG2DEV_2 (points[i].y + yoffset);
      CalcBoundingBox (points[i].x + xoffset, points[i].y + yoffset);
    }

  // Close figure for XDrawLines (not needed for XFillPolygon)
  xpoints1[i].x = xpoints1[0].x;
  xpoints1[i].y = xpoints1[0].y;
  xpoints2[i].x = xpoints2[0].x;
  xpoints2[i].y = xpoints2[0].y;

  if (current_brush && current_brush->GetStyle () != wxTRANSPARENT)
    {
      autoSetting = TRUE;	// must be reset

      SetBrush (current_brush);
      XSetFillRule (display, gc, fillStyle == wxODDEVEN_RULE ? EvenOddRule : WindingRule);
      XFillPolygon (display, pixmap, gc, xpoints1, n, Complex, 0);
      XSetFillRule (display, gc, EvenOddRule);	// default mode
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	{
	  XSetFillRule (display, gcBacking,
		   fillStyle == wxODDEVEN_RULE ? EvenOddRule : WindingRule);
	  XFillPolygon (display, canvas->backingPixmap, gcBacking, xpoints2, n, Complex, 0);
	  XSetFillRule (display, gcBacking, EvenOddRule);	// default mode

	}
#endif
    }

  if (current_pen && current_pen->GetStyle () != wxTRANSPARENT)
    {
      if (autoSetting)
	SetPen (current_pen);
      XDrawLines (display, pixmap, gc, xpoints1, n + 1, 0);
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	XDrawLines (display, canvas->backingPixmap, gcBacking, xpoints2, n + 1, 0);
#endif
    }

  delete[]xpoints1;
  delete[]xpoints2;
}

void wxCanvasDC:: DrawLines (int n, wxIntPoint points[], int xoffset, int yoffset)
{
  if (current_pen && current_pen->GetStyle () != wxTRANSPARENT)
    {
      if (autoSetting)
	SetPen (current_pen);

      XPoint *xpoints = new XPoint[n];
      int i;

      for (i = 0; i < n; i++)
	{
	  xpoints[i].x = XLOG2DEV (points[i].x + xoffset);
	  xpoints[i].y = YLOG2DEV (points[i].y + yoffset);
	}
      XDrawLines (display, pixmap, gc, xpoints, n, 0);
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	{
	  for (i = 0; i < n; i++)
	    {
	      xpoints[i].x = XLOG2DEV_2 (points[i].x + xoffset);
	      xpoints[i].y = YLOG2DEV_2 (points[i].y + yoffset);
	    }
	  XDrawLines (display, canvas->backingPixmap, gcBacking, xpoints, n, 0);
	}
#endif
      delete[]xpoints;
    }

}

void wxCanvasDC:: DrawLines (int n, wxPoint points[], float xoffset, float yoffset)
{
  if (current_pen && current_pen->GetStyle () != wxTRANSPARENT)
    {
      if (autoSetting)
	SetPen (current_pen);

      XPoint *xpoints = new XPoint[n];
      int i;

      for (i = 0; i < n; i++)
	{
	  xpoints[i].x = XLOG2DEV (points[i].x + xoffset);
	  xpoints[i].y = YLOG2DEV (points[i].y + yoffset);
	}

      XDrawLines (display, pixmap, gc, xpoints, n, 0);

#ifdef wx_motif
      if (canvas && canvas->is_retained)
	{
	  for (i = 0; i < n; i++)
	    {
	      xpoints[i].x = XLOG2DEV_2 (points[i].x + xoffset);
	      xpoints[i].y = YLOG2DEV_2 (points[i].y + yoffset);
	    }
	  XDrawLines (display, canvas->backingPixmap, gcBacking, xpoints, n, 0);
	}
#endif
      delete[]xpoints;
    }
}

void wxCanvasDC:: DrawRectangle (float x, float y, float width, float height)
{
  if (current_brush && current_brush->GetStyle () != wxTRANSPARENT)
    {
      autoSetting = TRUE;	// must be reset

      SetBrush (current_brush);
      XFillRectangle (display, pixmap, gc, XLOG2DEV (x), YLOG2DEV (y),
		      XLOG2DEVREL (width), YLOG2DEVREL (height));
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	XFillRectangle (display, canvas->backingPixmap, gcBacking, XLOG2DEV_2 (x), YLOG2DEV_2 (y),
			XLOG2DEVREL (width), YLOG2DEVREL (height));
#endif
    }

  if (current_pen && current_pen->GetStyle () != wxTRANSPARENT)
    {
      if (autoSetting)
	SetPen (current_pen);
      XDrawRectangle (display, pixmap, gc, XLOG2DEV (x), YLOG2DEV (y),
		      XLOG2DEVREL (width), YLOG2DEVREL (height));
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	XDrawRectangle (display, canvas->backingPixmap, gcBacking, XLOG2DEV_2 (x), YLOG2DEV_2 (y),
			XLOG2DEVREL (width), YLOG2DEVREL (height));
#endif
    }
  CalcBoundingBox (x, y);
  CalcBoundingBox (x + width, y + height);
}

void wxCanvasDC:: DrawRoundedRectangle (float x, float y, float width, float height, float radius)
{
  // If radius is negative, you can crash your ENTIRE X server. Wow!

  if (radius < 0.0)
    {
      // Now, a negative radius is interpreted to mean
      // 'the proportion of the smallest X or Y dimension'
      float smallest = 0.0;
      if (width < height)
	smallest = width;
      else
	smallest = height;
      radius = (float) (-radius * smallest);
    }

  int phys_x = XLOG2DEV (x);
  int phys_y = YLOG2DEV (y);
  int phys_radius = XLOG2DEVREL (radius);
  int phys_width = XLOG2DEVREL (width);
  int phys_height = YLOG2DEVREL (height);

  int phys_rwidth = phys_radius * 2;
  int phys_rheight = phys_rwidth;

#ifdef wx_motif
  int phys2_x = XLOG2DEV_2 (x);
  int phys2_y = YLOG2DEV_2 (y);
  int phys2_radius = XLOG2DEVREL (radius);
  int phys2_width = XLOG2DEVREL (width);
  int phys2_height = YLOG2DEVREL (height);

  int phys2_rwidth = phys2_radius * 2;
  int phys2_rheight = phys2_rwidth;
#endif

  if (current_brush && current_brush->GetStyle () != wxTRANSPARENT)
    {
      autoSetting = TRUE;	// must be reset

      SetBrush (current_brush);

      XFillRectangle (display, pixmap, gc, phys_x + phys_radius, phys_y,
		      phys_width - phys_rwidth, phys_height);
      XFillRectangle (display, pixmap, gc, phys_x, phys_y + phys_radius,
		      phys_width, phys_height - phys_rheight);

      XFillArc (display, pixmap, gc, phys_x, phys_y,
		phys_rwidth, phys_rheight, 90 * 64, 90 * 64);
      XFillArc (display, pixmap, gc, phys_x + phys_width - phys_rwidth, phys_y,
		phys_rwidth, phys_rheight, 0, 90 * 64);
      XFillArc (display, pixmap, gc, phys_x + phys_width - phys_rwidth,
		phys_y + phys_height - phys_rheight,
		phys_rwidth, phys_rheight, 270 * 64, 90 * 64);
      XFillArc (display, pixmap, gc, phys_x, phys_y + phys_height - phys_rheight,
		phys_rwidth, phys_rheight, 180 * 64, 90 * 64);

#ifdef wx_motif
      if (canvas && canvas->is_retained)
	{
	  XFillRectangle (display, canvas->backingPixmap, gcBacking,
			  phys2_x + phys2_radius, phys2_y, phys2_width - phys2_rwidth, phys2_height);
	  XFillRectangle (display, canvas->backingPixmap, gcBacking,
			  phys2_x, phys2_y + phys2_radius, phys2_width, phys2_height - phys2_rheight);

	  XFillArc (display, canvas->backingPixmap, gcBacking,
	   phys2_x, phys2_y, phys2_rwidth, phys2_rheight, 90 * 64, 90 * 64);
	  XFillArc (display, canvas->backingPixmap, gcBacking,
		    phys2_x + phys2_width - phys2_rwidth, phys2_y,
		    phys2_rwidth, phys2_rheight, 0, 90 * 64);
	  XFillArc (display, canvas->backingPixmap, gcBacking,
		    phys2_x + phys2_width - phys2_rwidth,
		    phys2_y + phys2_height - phys2_rheight,
		    phys2_rwidth, phys2_rheight, 270 * 64, 90 * 64);
	  XFillArc (display, canvas->backingPixmap, gcBacking,
		    phys2_x, phys2_y + phys2_height - phys2_rheight,
		    phys2_rwidth, phys2_rheight, 180 * 64, 90 * 64);
	}
#endif
    }

  if (current_pen && current_pen->GetStyle () != wxTRANSPARENT)
    {
      if (autoSetting)
	SetPen (current_pen);
      XDrawLine (display, pixmap, gc, phys_x + phys_radius, phys_y,
		 phys_x + phys_width - phys_radius, phys_y);
      XDrawLine (display, pixmap, gc, phys_x + phys_radius, phys_y + phys_height,
		 phys_x + phys_width - phys_radius, phys_y + phys_height);

      XDrawLine (display, pixmap, gc, phys_x, phys_y + phys_radius,
		 phys_x, phys_y + phys_height - phys_radius);
      XDrawLine (display, pixmap, gc, phys_x + phys_width, phys_y + phys_radius,
		 phys_x + phys_width, phys_y + phys_height - phys_radius);
      XDrawArc (display, pixmap, gc, phys_x, phys_y,
		phys_rwidth, phys_rheight, 90 * 64, 90 * 64);
      XDrawArc (display, pixmap, gc, phys_x + phys_width - phys_rwidth, phys_y,
		phys_rwidth, phys_rheight, 0, 90 * 64);
      XDrawArc (display, pixmap, gc, phys_x + phys_width - phys_rwidth,
		phys_y + phys_height - phys_rheight,
		phys_rwidth, phys_rheight, 270 * 64, 90 * 64);
      XDrawArc (display, pixmap, gc, phys_x, phys_y + phys_height - phys_rheight,
		phys_rwidth, phys_rheight, 180 * 64, 90 * 64);
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	{
	  XDrawLine (display, canvas->backingPixmap, gcBacking,
		     phys2_x + phys2_radius, phys2_y,
		     phys2_x + phys2_width - phys2_radius, phys2_y);
	  XDrawLine (display, canvas->backingPixmap, gcBacking,
		     phys2_x + phys2_radius, phys2_y + phys2_height,
	      phys2_x + phys2_width - phys2_radius, phys2_y + phys2_height);

	  XDrawLine (display, canvas->backingPixmap, gcBacking,
		     phys2_x, phys2_y + phys2_radius,
		     phys2_x, phys2_y + phys2_height - phys2_radius);
	  XDrawLine (display, canvas->backingPixmap, gcBacking,
		     phys2_x + phys2_width, phys2_y + phys2_radius,
	      phys2_x + phys2_width, phys2_y + phys2_height - phys2_radius);
	  XDrawArc (display, canvas->backingPixmap, gcBacking,
		    phys2_x, phys2_y,
		    phys2_rwidth, phys2_rheight, 90 * 64, 90 * 64);
	  XDrawArc (display, canvas->backingPixmap, gcBacking,
		    phys2_x + phys2_width - phys2_rwidth, phys2_y,
		    phys2_rwidth, phys2_rheight, 0, 90 * 64);
	  XDrawArc (display, canvas->backingPixmap, gcBacking,
		    phys2_x + phys2_width - phys2_rwidth,
		    phys2_y + phys2_height - phys2_rheight,
		    phys2_rwidth, phys2_rheight, 270 * 64, 90 * 64);
	  XDrawArc (display, canvas->backingPixmap, gcBacking,
		    phys2_x, phys2_y + phys2_height - phys2_rheight,
		    phys2_rwidth, phys2_rheight, 180 * 64, 90 * 64);
	}
#endif
    }
  CalcBoundingBox (x, y);
  CalcBoundingBox (x + width, y + height);
}

void wxCanvasDC:: DrawEllipse (float x, float y, float width, float height)
{
  static const int angle = 23040;

  if (current_brush && current_brush->GetStyle () != wxTRANSPARENT)
    {
      autoSetting = TRUE;	// must be reset

      SetBrush (current_brush);
      XFillArc (display, pixmap, gc, XLOG2DEV (x), YLOG2DEV (y),
		XLOG2DEVREL (width), YLOG2DEVREL (height), 0, angle);
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	XFillArc (display, canvas->backingPixmap, gcBacking, XLOG2DEV_2 (x), YLOG2DEV_2 (y),
		  XLOG2DEVREL (width), YLOG2DEVREL (height), 0, angle);
#endif
    }

  if (current_pen && current_pen->GetStyle () != wxTRANSPARENT)
    {
      if (autoSetting)
	SetPen (current_pen);
      XDrawArc (display, pixmap, gc, XLOG2DEV (x), YLOG2DEV (y),
		XLOG2DEVREL (width), YLOG2DEVREL (height), 0, angle);
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	XDrawArc (display, canvas->backingPixmap, gcBacking, XLOG2DEV_2 (x), YLOG2DEV_2 (y),
		  XLOG2DEVREL (width), YLOG2DEVREL (height), 0, angle);
#endif
    }
  CalcBoundingBox (x, y);
  CalcBoundingBox (x + width, y + height);
}

void wxCanvasDC:: DrawIcon (wxIcon * icon, float x, float y)
{
  // Be sure that foreground pixels (1) of
  // the Icon will be painted with pen colour. [current_pen->SetColour()]
  // Background pixels (0) will be painted with 
  // last selected background color. [::SetBackground]
  if (current_pen && autoSetting)
    SetPen (current_pen);

  int width, height;
#ifdef wx_xview
  Pixmap iconPixmap = (Pixmap) xv_get (icon->x_image, SERVER_IMAGE_PIXMAP);
  width = (int) xv_get (icon->x_image, XV_WIDTH);
  height = (int) xv_get (icon->x_image, XV_HEIGHT);
#endif
#ifdef wx_motif
  Pixmap iconPixmap = icon->x_pixmap;
  width = icon->GetWidth();
  height = icon->GetHeight();
#endif
  XCopyPlane (display, iconPixmap, pixmap, gc,
	    0, 0, width, height, (int) XLOG2DEV (x), (int) YLOG2DEV (y), 1);
/***
An other way to draw icons. Experimental.
XCopyPlane seems to be confused if logical function is not wxCOPY, so
we try to use stippling. Or is it me, who is confused?

  XSetStipple(display,gc,iconPixmap) ;
  XSetFillStyle(display,gc,FillOpaqueStippled) ;
  XSetTSOrigin(display,gc,(int)XLOG2DEV(x),(int)YLOG2DEV(y)) ;
  XFillRectangle(display,pixmap,gc,(int)XLOG2DEV(x),(int)YLOG2DEV(y),width,height) ;
  XSetFillStyle(display,gc,FillSolid) ;
***/

#ifdef wx_motif
  if (canvas && canvas->is_retained)
    XCopyPlane (display, iconPixmap, canvas->backingPixmap, gcBacking,
	0, 0, width, height, (int) XLOG2DEV_2 (x), (int) YLOG2DEV_2 (y), 1);
#endif
  CalcBoundingBox (x, y);
}

void wxCanvasDC:: SetFont (wxFont * the_font)
{
  font = the_font;
  if (!font)
    return;
#ifdef wx_xview
  // Set the font according to the current scaling
  int scaled_size = (int) (user_scale_y * font->GetPointSize () + 0.5);
  Xv_Font xfont = wxFontPool->FindNearestFont (font->GetFamily (), font->GetStyle (),
	     font->GetWeight (), scaled_size, font->GetUnderlined (), 0, 0);
  font->x_font = xfont;
  Font theFont = (Font) xv_get (xfont, XV_XID);
#endif
#ifdef wx_motif
/*
   int res_x = (int)(DisplayWidth(dpy, screen)/(DisplayWidthMM(dpy, screen)/25.4));
   int res_y = (int)(DisplayHeight(dpy, screen)/(DisplayHeightMM(dpy, screen)/25.4));
 */
  int res_x = 100;
  int res_y = 100;

  int scaled_size = (int) (10 * ((int) (user_scale_y * font->GetPointSize () + 0.5)));

  XFontStruct *fontStruct = wxFontPool->FindNearestFont (font->GetFamily (), font->GetStyle (),
					    font->GetWeight (), scaled_size,
				      font->GetUnderlined (), res_x, res_y);
  font->xFont = fontStruct;
  Font theFont = fontStruct->fid;
#endif
  XSetFont (display, gc, theFont);
#ifdef wx_motif
  if (canvas && canvas->is_retained)
    XSetFont (display, gcBacking, theFont);
#endif
}

void wxCanvasDC:: SetPen (wxPen * pen)
{
  wxBitmap *old_stipple = current_stipple;
  int old_style = current_style;
  int old_fill = current_fill;
  int old_pen_width = current_pen_width;
  int old_pen_join = current_pen_join;
  int old_pen_cap = current_pen_cap;
  int old_pen_nb_dash = current_pen_nb_dash;
  char *old_pen_dash = current_pen_dash;
  current_pen = pen;
  if (!pen)
    return;

  wxColour old_pen_colour = current_colour;
  current_colour = pen->GetColour ();
  current_style = pen->GetStyle ();
  current_fill = pen->GetStyle ();
  current_pen_width = pen->GetWidth ();
  current_pen_join = pen->GetJoin ();
  current_pen_cap = pen->GetCap ();
  current_pen_nb_dash = pen->nb_dash;
  current_pen_dash = pen->dash;
  if (current_style == wxSTIPPLE)
    current_stipple = pen->GetStipple ();

  Bool same_style = (old_style == current_style &&
		     old_fill == current_fill &&
		     old_pen_join == current_pen_join &&
		     old_pen_cap == current_pen_cap &&
		     old_pen_nb_dash == current_pen_nb_dash &&
		     old_pen_dash == current_pen_dash &&
		     old_pen_width == current_pen_width);

  Bool same_colour = (old_pen_colour.Ok () &&
		      (old_pen_colour.Red () == current_colour.Red ()) &&
		      (old_pen_colour.Blue () == current_colour.Blue ()) &&
		      (old_pen_colour.Green () == current_colour.Green ()) &&
		      (old_pen_colour.pixel == current_colour.pixel));

  if (!same_style || !dcOptimize)
    {
      int scaled_width = (int) XLOG2DEVREL (pen->GetWidth ());
      if (scaled_width < 0)
	scaled_width = 0;

      int style;
      int join;
      int cap;
      static char dotted[] =
      {2, 5};
      static char short_dashed[] =
      {4, 4};
      static char long_dashed[] =
      {4, 8};
      static char dotted_dashed[] =
      {6, 6, 2, 6};

      // We express dash pattern in pen width unit, so we are
      // independent of zoom factor and so on...
      int req_nb_dash;
      char *req_dash;

      switch (pen->GetStyle ())
	{
	case wxUSER_DASH:
	  req_nb_dash = current_pen_nb_dash;
	  req_dash = current_pen_dash;
	  style = LineOnOffDash;
	  break;
	case wxDOT:
	  req_nb_dash = 2;
	  req_dash = dotted;
	  style = LineOnOffDash;
	  break;
	case wxSHORT_DASH:
	  req_nb_dash = 2;
	  req_dash = short_dashed;
	  style = LineOnOffDash;
	  break;
	case wxLONG_DASH:
	  req_nb_dash = 2;
	  req_dash = long_dashed;
	  style = LineOnOffDash;
	  break;
	case wxDOT_DASH:
	  req_nb_dash = 4;
	  req_dash = dotted_dashed;
	  style = LineOnOffDash;
	  break;
	case wxSTIPPLE:
	case wxSOLID:
	case wxTRANSPARENT:
	default:
	  style = LineSolid;
	  req_dash = NULL;
	  req_nb_dash = 0;
	}

      if (req_dash && req_nb_dash)
	{
	  char *real_req_dash = new char[req_nb_dash];
	  if (real_req_dash)
	    {
	      int factor = scaled_width == 0 ? 1 : scaled_width;
	      for (int i = 0; i < req_nb_dash; i++)
		real_req_dash[i] = req_dash[i] * factor;
	      XSetDashes (display, gc, 0, real_req_dash, req_nb_dash);
#ifdef wx_motif
	      if (canvas && canvas->is_retained)
		XSetDashes (display, gcBacking, 0, real_req_dash, req_nb_dash);
#endif
	      delete[]real_req_dash;
	    }
	  else
	    {
	      // No Memory. We use non-scaled dash pattern...
	      XSetDashes (display, gc, 0, req_dash, req_nb_dash);
#ifdef wx_motif
	      if (canvas && canvas->is_retained)
		XSetDashes (display, gcBacking, 0, req_dash, req_nb_dash);
#endif
	    }
	}

      switch (pen->GetCap ())
	{
	case wxCAP_PROJECTING:
	  cap = CapProjecting;
	  break;
	case wxCAP_BUTT:
	  cap = CapButt;
	  break;
	case wxCAP_ROUND:
	default:
	  cap = CapRound;
	  break;
	}

      switch (pen->GetJoin ())
	{
	case wxJOIN_BEVEL:
	  join = JoinBevel;
	  break;
	case wxJOIN_MITER:
	  join = JoinMiter;
	  break;
	case wxJOIN_ROUND:
	default:
	  join = JoinRound;
	  break;
	}

      XSetLineAttributes (display, gc, scaled_width, style, cap, join);
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	XSetLineAttributes (display, gcBacking, scaled_width, style, cap, join);
#endif
    }

  if (IS_HATCH (current_fill) && ((current_fill != old_fill) || !dcOptimize))
    {
      Pixmap my_stipple;

      old_stipple = NULL;	// For later reset!!

      switch (current_fill)
	{
	case wxBDIAGONAL_HATCH:
	  if (bdiag == (Pixmap) 0)
	    bdiag = XCreateBitmapFromData (display,
			      RootWindow (display, DefaultScreen (display)),
				     bdiag_bits, bdiag_width, bdiag_height);
	  my_stipple = bdiag;
	  break;
	case wxFDIAGONAL_HATCH:
	  if (fdiag == (Pixmap) 0)
	    fdiag = XCreateBitmapFromData (display,
			      RootWindow (display, DefaultScreen (display)),
				     fdiag_bits, fdiag_width, fdiag_height);
	  my_stipple = fdiag;
	  break;
	case wxCROSS_HATCH:
	  if (cross == (Pixmap) 0)
	    cross = XCreateBitmapFromData (display,
			      RootWindow (display, DefaultScreen (display)),
				     cross_bits, cross_width, cross_height);
	  my_stipple = cross;
	  break;
	case wxHORIZONTAL_HATCH:
	  if (horiz == (Pixmap) 0)
	    horiz = XCreateBitmapFromData (display,
			      RootWindow (display, DefaultScreen (display)),
				     horiz_bits, horiz_width, horiz_height);
	  my_stipple = horiz;
	  break;
	case wxVERTICAL_HATCH:
	  if (verti == (Pixmap) 0)
	    verti = XCreateBitmapFromData (display,
			      RootWindow (display, DefaultScreen (display)),
				     verti_bits, verti_width, verti_height);
	  my_stipple = verti;
	  break;
	case wxCROSSDIAG_HATCH:
	default:
	  if (cdiag == (Pixmap) 0)
	    cdiag = XCreateBitmapFromData (display,
			      RootWindow (display, DefaultScreen (display)),
				     cdiag_bits, cdiag_width, cdiag_height);
	  my_stipple = cdiag;
	  break;
	}
      XSetStipple (display, gc, my_stipple);
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	XSetStipple (display, gcBacking, my_stipple);
#endif
    }
  else if (current_stipple && ((current_stipple != old_stipple) || !dcOptimize))
    {
      XSetStipple (display, gc, current_stipple->x_pixmap);
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	XSetStipple (display, gcBacking, current_stipple->x_pixmap);
#endif
    }

  if ((current_fill != old_fill) || !dcOptimize)
    {
      int fill_style;

      if (current_fill == wxSTIPPLE)
	fill_style = FillStippled;
      else if (IS_HATCH (current_fill))
	fill_style = FillStippled;
      else
	fill_style = FillSolid;
      XSetFillStyle (display, gc, fill_style);
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	XSetFillStyle (display, gcBacking, fill_style);
#endif
    }

  // must test current_logical_function, because it involves background!
  if (!same_colour || !dcOptimize || current_logical_function == wxXOR)
    {
      int pixel = -1;
      if (pen->GetStyle () == wxTRANSPARENT)
	pixel = background_pixel;
      else if (!Colour)
	{
	  unsigned char red = pen->GetColour ().Red ();
	  unsigned char blue = pen->GetColour ().Blue ();
	  unsigned char green = pen->GetColour ().Green ();
	  if (red == (unsigned char) 255 && blue == (unsigned char) 255
	      && green == (unsigned char) 255)
	    {
	      pixel = (int) WhitePixel (display, DefaultScreen (display));
	      current_colour = *wxWHITE;
	      current_pen->GetColour().pixel = current_colour.pixel = pixel;
	    }
	  else
	    {
	      pixel = (int) BlackPixel (display, DefaultScreen (display));
	      current_colour = *wxBLACK;
	      current_pen->GetColour().pixel = current_colour.pixel = pixel;
	    }
	}
      else
	{
	  if (pen->GetColour ().pixel != -1)
	    pixel = pen->GetColour ().pixel;
	  else
	    {
	      XColor exact_def;
	      exact_def.red = (unsigned short) (((long) pen->GetColour ().Red ()) << 8);
	      exact_def.green = (unsigned short) (((long) pen->GetColour ().Green ()) << 8);
	      exact_def.blue = (unsigned short) (((long) pen->GetColour ().Blue ()) << 8);
	      exact_def.flags = DoRed | DoGreen | DoBlue;

//   Colormap cmap = DefaultColormap(display, DefaultScreen(display));
	      Colormap cmap = wxMainColormap;
#ifdef wx_motif
	      if (!YAllocColor (XtDisplay (wxTheApp->topLevel), cmap, &exact_def))
#else
	      if (!YAllocColor (display, cmap, &exact_def))
#endif
		{
		  pixel = (int) BlackPixel (display, DefaultScreen (display));
		  cerr << "wxWindows warning: cannot allocate pen colour; using black instead\n";
		}
	      else
		pixel = (int) exact_def.pixel;
	      current_colour.pixel = pen->GetColour().pixel = pixel;
	    }
	}

      // Finally, set the GC to the required colour
      if (pixel > -1)
	{
	  if (current_logical_function == wxXOR)
	    {
	      XGCValues values;
	      XGetGCValues (display, gc, GCBackground, &values);
	      XSetForeground (display, gc, pixel ^ values.background);
#ifdef wx_motif
	      if (canvas && canvas->is_retained)
		XSetForeground (display, gcBacking, pixel ^ values.background);
#endif
	    }
	  else
	    {
	      XSetForeground (display, gc, pixel);
#ifdef wx_motif
	      if (canvas && canvas->is_retained)
		XSetForeground (display, gcBacking, pixel);
#endif
	    }
	}
    }
  else
    pen->GetColour().pixel = old_pen_colour.pixel;

}

void wxCanvasDC:: SetBrush (wxBrush * brush)
{
  int old_fill = current_fill;
  wxBitmap *old_stipple = current_stipple;

  current_brush = brush;
  if (!brush || brush->GetStyle () == wxTRANSPARENT)
    return;

  current_fill = current_brush->GetStyle ();
  if (current_fill == wxSTIPPLE)
    current_stipple = current_brush->GetStipple ();

  wxColour old_brush_colour(current_colour);
  current_colour = brush->GetColour ();
  Bool same_colour = (old_brush_colour.Ok () &&
		      (old_brush_colour.Red () == current_colour.Red ()) &&
		      (old_brush_colour.Blue () == current_colour.Blue ()) &&
		   (old_brush_colour.Green () == current_colour.Green ()) &&
		      (old_brush_colour.pixel == current_colour.pixel));

  if ((old_fill != brush->GetStyle ()) || !dcOptimize)
    {
      switch (brush->GetStyle ())
	{
	case wxTRANSPARENT:
	  break;
	case wxBDIAGONAL_HATCH:
	case wxCROSSDIAG_HATCH:
	case wxFDIAGONAL_HATCH:
	case wxCROSS_HATCH:
	case wxHORIZONTAL_HATCH:
	case wxVERTICAL_HATCH:
	case wxSTIPPLE:
	  XSetFillStyle (display, gc, FillStippled);
#ifdef wx_motif
	  if (canvas && canvas->is_retained)
	    XSetFillStyle (display, gcBacking, FillStippled);
#endif
	  break;
	case wxSOLID:
	default:
	  XSetFillStyle (display, gc, FillSolid);
#ifdef wx_motif
	  if (canvas && canvas->is_retained)
	    XSetFillStyle (display, gcBacking, FillSolid);
#endif
	}
    }

  if (IS_HATCH (current_fill) && ((current_fill != old_fill) || !dcOptimize))
    {
      Pixmap my_stipple;

      old_stipple = NULL;	// For later reset!!

      switch (current_fill)
	{
	case wxBDIAGONAL_HATCH:
	  if (bdiag == (Pixmap) 0)
	    bdiag = XCreateBitmapFromData (display,
			      RootWindow (display, DefaultScreen (display)),
				     bdiag_bits, bdiag_width, bdiag_height);
	  my_stipple = bdiag;
	  break;
	case wxFDIAGONAL_HATCH:
	  if (fdiag == (Pixmap) 0)
	    fdiag = XCreateBitmapFromData (display,
			      RootWindow (display, DefaultScreen (display)),
				     fdiag_bits, fdiag_width, fdiag_height);
	  my_stipple = fdiag;
	  break;
	case wxCROSS_HATCH:
	  if (cross == (Pixmap) 0)
	    cross = XCreateBitmapFromData (display,
			      RootWindow (display, DefaultScreen (display)),
				     cross_bits, cross_width, cross_height);
	  my_stipple = cross;
	  break;
	case wxHORIZONTAL_HATCH:
	  if (horiz == (Pixmap) 0)
	    horiz = XCreateBitmapFromData (display,
			      RootWindow (display, DefaultScreen (display)),
				     horiz_bits, horiz_width, horiz_height);
	  my_stipple = horiz;
	  break;
	case wxVERTICAL_HATCH:
	  if (verti == (Pixmap) 0)
	    verti = XCreateBitmapFromData (display,
			      RootWindow (display, DefaultScreen (display)),
				     verti_bits, verti_width, verti_height);
	  my_stipple = verti;
	  break;
	case wxCROSSDIAG_HATCH:
	default:
	  if (cdiag == (Pixmap) 0)
	    cdiag = XCreateBitmapFromData (display,
			      RootWindow (display, DefaultScreen (display)),
				     cdiag_bits, cdiag_width, cdiag_height);
	  my_stipple = cdiag;
	  break;
	}
      XSetStipple (display, gc, my_stipple);
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	XSetStipple (display, gcBacking, my_stipple);
#endif
    }
  else if (current_stipple && current_stipple != old_stipple)
    {
      XSetStipple (display, gc, current_stipple->x_pixmap);
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	XSetStipple (display, gcBacking, current_stipple->x_pixmap);
#endif
    }

  // must test current_logical_function, because it involves background!
  if (!same_colour || !dcOptimize || current_logical_function == wxXOR)
    {
      int pixel = -1;
      if (!Colour)
	{
	  // Policy - on a monochrome screen, all brushes are white,
	  // except when they're REALLY black!!!
	  unsigned char red = brush->GetColour ().Red ();
	  unsigned char blue = brush->GetColour ().Blue ();
	  unsigned char green = brush->GetColour ().Green ();

	  if (red == (unsigned char) 0 && blue == (unsigned char) 0
	      && green == (unsigned char) 0)
	    {
	      pixel = (int) BlackPixel (display, DefaultScreen (display));
	      current_colour = *wxBLACK;
	      current_brush->GetColour().pixel = current_colour.pixel = pixel;
	    }
	  else
	    {
	      pixel = (int) WhitePixel (display, DefaultScreen (display));
	      current_colour = *wxWHITE;
	      current_brush->GetColour().pixel = current_colour.pixel = pixel;
	    }

	  // N.B. comment out the above line and uncomment the following lines
	  // if you want non-white colours to be black on a monochrome display.
	  /*
	     if (red == (unsigned char )255 && blue == (unsigned char)255
	     && green == (unsigned char)255)
	     pixel = (int)WhitePixel(display, DefaultScreen(display));
	     else
	     pixel = (int)BlackPixel(display, DefaultScreen(display));
	   */
	}
      else if (brush->GetStyle () != wxTRANSPARENT)
	{
	  if (brush->GetColour ().pixel > -1)
	    pixel = brush->GetColour ().pixel;
	  else
	    {
	      XColor exact_def;
	      exact_def.red = (unsigned short) (((long) brush->GetColour ().Red ()) << 8);
	      exact_def.green = (unsigned short) (((long) brush->GetColour ().Green ()) << 8);
	      exact_def.blue = (unsigned short) (((long) brush->GetColour ().Blue ()) << 8);
	      exact_def.flags = DoRed | DoGreen | DoBlue;

//        Colormap cmap = DefaultColormap(display, DefaultScreen(display));
	      Colormap cmap = wxMainColormap;

	      if (!YAllocColor (display, cmap, &exact_def))
		{
		  pixel = (int) BlackPixel (display, DefaultScreen (display));
		  cerr << "wxWindows warning: cannot allocate brush colour; using black instead\n";
		}
	      else
		pixel = (int) exact_def.pixel;
	      current_colour.pixel = brush->GetColour().pixel = pixel;
	    }
	}
      if (pixel > -1)
	{
	  // Finally, set the GC to the required colour
	  if (current_logical_function == wxXOR)
	    {
	      XGCValues values;
	      XGetGCValues (display, gc, GCBackground, &values);
	      XSetForeground (display, gc, pixel ^ values.background);
#ifdef wx_motif
	      if (canvas && canvas->is_retained)
		XSetForeground (display, gcBacking, pixel ^ values.background);
#endif
	    }
	  else
	    {
	      XSetForeground (display, gc, pixel);
#ifdef wx_motif
	      if (canvas && canvas->is_retained)
		XSetForeground (display, gcBacking, pixel);
#endif
	    }
	}
    }
  else
    brush->GetColour().pixel = old_brush_colour.pixel;
  //current_colour.pixel = brush->colour-pixel = old_brush_colour.pixel ;
}

void wxCanvasDC::SetColourMap(wxColourMap *cmap)
{
  if (canvas)
  {
    if (cmap)
      XSetWindowColormap (display, canvas->xwindow, cmap->cmap);
    else
      XSetWindowColormap (display, canvas->xwindow, wxMainColormap);
  }
}


void wxCanvasDC:: DrawText (const char *text, float x, float y)
{
  // Since X draws from the baseline of the text, must
  // add the text height
  int cx = 0;
  int cy = 0;
  int ascent = 0;
  if (font)
    {
#ifdef wx_xview
      XFontStruct *font_info = (XFontStruct *) xv_get (font->x_font, FONT_INFO);
#endif
#ifdef wx_motif
      XFontStruct *font_info = font->xFont;
#endif
      int direction, descent;
      XCharStruct overall_return;
      (void) XTextExtents (font_info, text, strlen (text), &direction,
			   &ascent, &descent, &overall_return);
      cx = overall_return.width;
      cy = ascent + descent;
    }

  // First draw a rectangle representing the text background,
  // if a text background is specified
  if (current_text_background.Ok () && (current_bk_mode != wxTRANSPARENT))
    {
      wxColour old_pen_colour = current_colour;
      current_colour = current_text_background;
      Bool same_colour = (old_pen_colour.Ok () && current_text_background.Ok () &&
		(old_pen_colour.Red () == current_text_background.Red ()) &&
	      (old_pen_colour.Blue () == current_text_background.Blue ()) &&
	    (old_pen_colour.Green () == current_text_background.Green ()) &&
		   (old_pen_colour.pixel == current_text_background.pixel));

      if (!same_colour || !dcOptimize)
	{
	  int pixel = -1;
	  if (current_text_background.Ok ())
	    {
	      if (current_text_background.pixel > -1)
		pixel = current_text_background.pixel;
	      else
		{
		  XColor exact_def;
		  exact_def.red = (unsigned short) (((long) current_text_background.Red ()) << 8);
		  exact_def.green = (unsigned short) (((long) current_text_background.Green ()) << 8);
		  exact_def.blue = (unsigned short) (((long) current_text_background.Blue ()) << 8);
		  exact_def.flags = DoRed | DoGreen | DoBlue;

//     Colormap cmap = DefaultColormap(display, DefaultScreen(display));
		  Colormap cmap = wxMainColormap;

		  if (!YAllocColor (display, cmap, &exact_def))
		    {
		      pixel = (int) WhitePixel (display, DefaultScreen (display));
		      cerr << "wxWindows warning: cannot allocate text background colour; using white instead\n";
		    }
		  else
		    pixel = (int) exact_def.pixel;
		  current_colour.pixel = current_text_background.pixel = pixel;
		}
	    }
	  // Set the GC to the required colour
	  if (pixel > -1)
	    {
	      XSetForeground (display, gc, pixel);
#ifdef wx_motif
	      if (canvas && canvas->is_retained)
		XSetForeground (display, gcBacking, pixel);
#endif
	    }
	}
      else
	current_text_background.pixel = old_pen_colour.pixel;

      XFillRectangle (display, pixmap, gc, XLOG2DEV (x), YLOG2DEV (y), cx, cy);
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	XFillRectangle (display, canvas->backingPixmap, gcBacking,
			XLOG2DEV_2 (x), YLOG2DEV_2 (y), cx, cy);
#endif
    }

  // Now set the text foreground and draw the text
  if (current_text_foreground.Ok ())
    {
      wxColour old_pen_colour = current_colour;
      current_colour = current_text_foreground;
      Bool same_colour = (old_pen_colour.Ok () && current_colour.Ok () &&
			  (old_pen_colour.Red () == current_colour.Red ()) &&
		       (old_pen_colour.Blue () == current_colour.Blue ()) &&
		     (old_pen_colour.Green () == current_colour.Green ()) &&
			  (old_pen_colour.pixel == current_colour.pixel));

      if (!same_colour || !dcOptimize)
	{
	  int pixel = -1;
	  if (!Colour)
	    {
	      // Unless foreground is really white, draw it in black
	      unsigned char red = current_text_foreground.Red ();
	      unsigned char blue = current_text_foreground.Blue ();
	      unsigned char green = current_text_foreground.Green ();
	      if (red == (unsigned char) 255 && blue == (unsigned char) 255
		  && green == (unsigned char) 255)
		{
		  pixel = (int) WhitePixel (display, DefaultScreen (display));
		  current_colour = *wxWHITE;
		  current_colour.pixel = current_text_foreground.pixel = pixel;
		}
	      else
		{
		  pixel = (int) BlackPixel (display, DefaultScreen (display));
		  current_colour = *wxBLACK;
		  current_colour.pixel = current_text_foreground.pixel = pixel;
		}
	    }
	  else
	    {
	      if (current_text_foreground.pixel > -1)
		pixel = current_text_foreground.pixel;
	      else
		{
		  XColor exact_def;
		  exact_def.red = (unsigned short) (((long) current_text_foreground.Red ()) << 8);
		  exact_def.green = (unsigned short) (((long) current_text_foreground.Green ()) << 8);
		  exact_def.blue = (unsigned short) (((long) current_text_foreground.Blue ()) << 8);
		  exact_def.flags = DoRed | DoGreen | DoBlue;

//       Colormap cmap = DefaultColormap(display, DefaultScreen(display));
		  Colormap cmap = wxMainColormap;

		  if (!YAllocColor (display, cmap, &exact_def))
		    {
		      pixel = (int) BlackPixel (display, DefaultScreen (display));
		      cerr << "wxWindows warning: cannot allocate text colour; using black instead\n";
		    }
		  else
		    pixel = (int) exact_def.pixel;
		  current_colour.pixel = current_text_foreground.pixel = pixel;
		}
	    }

	  // Set the GC to the required colour
	  if (pixel > -1)
	    {
	      XSetForeground (display, gc, pixel);
#ifdef wx_motif
	      if (canvas && canvas->is_retained)
		XSetForeground (display, gcBacking, pixel);
#endif
	    }
	}
      else
	current_text_foreground.pixel = old_pen_colour.pixel;
    }

  // We need to add the ascent, not the whole height, since X draws
  // at the point above the descender.
  XDrawString (display, pixmap, gc,
	       XLOG2DEV (x), YLOG2DEV (y) + ascent, text, strlen (text));
#ifdef wx_motif
  if (canvas && canvas->is_retained)
    XDrawString (display, canvas->backingPixmap, gcBacking,
	      XLOG2DEV_2 (x), YLOG2DEV_2 (y) + ascent, text, strlen (text));
#endif
  float w, h;
  GetTextExtent (text, &w, &h);
  CalcBoundingBox (x + w, y + h);
  CalcBoundingBox (x, y);
}

void wxCanvasDC:: SetBackground (wxBrush * brush)
{
  int pixel;

  current_background_brush = brush;

  if (!canvas)
    return;

  if (!brush)
    return;

  pixel = brush->GetColour ().pixel;

  if (current_background_brush)
    {
      if (current_background_brush->GetColour ().pixel > -1)
	pixel = current_background_brush->GetColour ().pixel;
      else
	{
	  XColor exact_def;
	  exact_def.red = (unsigned short) (((long) brush->GetColour ().Red ()) << 8);
	  exact_def.green = (unsigned short) (((long) brush->GetColour ().Green ()) << 8);
	  exact_def.blue = (unsigned short) (((long) brush->GetColour ().Blue ()) << 8);
	  exact_def.flags = DoRed | DoGreen | DoBlue;

//    Colormap cmap = DefaultColormap(display, DefaultScreen(display));
	  Colormap cmap = wxMainColormap;

	  if (!YAllocColor (display, cmap, &exact_def))
	    {
	      pixel = (int) WhitePixel (display, DefaultScreen (display));
	      cerr << "wxWindows warning: cannot allocate background colour; using white instead\n";
	    }
	  else
	    pixel = (int) exact_def.pixel;
	  current_background_brush->GetColour().pixel = pixel;
	}


#ifdef wx_xview
      // Finally, set the background to the required colour
      Xv_Window pw = canvas_paint_window ((Canvas) (canvas->handle));

      Window win = (Window) xv_get (pw, XV_XID);
      XSetWindowBackground (display, win, pixel);
      // Necessary for ::DrawIcon, which use fg/bg pixel or the GC.
      // And Blit,... (Any fct that use XCopyPlane, in fact.)
      XSetBackground (display, gc, pixel);
#endif
#ifdef wx_motif
      XSetWindowBackground (display, pixmap, pixel);
      if (canvas && canvas->is_retained)
	XSetWindowBackground (display, canvas->backingPixmap, pixel);
      // Necessary for ::DrawIcon, which use fg/bg pixel or the GC.
      // And Blit,... (Any fct that use XCopyPlane, in fact.)
      XSetBackground (display, gc, pixel);
      if (canvas && canvas->is_retained)
	XSetBackground (display, gcBacking, pixel);
#endif
    }
}

void wxCanvasDC:: SetLogicalFunction (int function)
{
  int x_function;
  switch (function)
    {
    case wxCLEAR:
      x_function = GXclear;
      break;
    case wxXOR:
      x_function = GXxor;
      break;
    case wxINVERT:
      x_function = GXinvert;
      break;
    case wxOR_REVERSE:
      x_function = GXorReverse;
      break;
    case wxAND_REVERSE:
      x_function = GXandReverse;
      break;
    case wxAND:
      x_function = GXand;
      break;
    case wxOR:
      x_function = GXor;
      break;
    case wxAND_INVERT:
      x_function = GXandInverted;
      break;
    case wxNO_OP:
      x_function = GXnoop;
      break;
    case wxNOR:
      x_function = GXnor;
      break;
    case wxEQUIV:
      x_function = GXequiv;
      break;
    case wxSRC_INVERT:
      x_function = GXcopyInverted;
      break;
    case wxOR_INVERT:
      x_function = GXorInverted;
      break;
    case wxNAND:
      x_function = GXnand;
      break;
    case wxSET:
      x_function = GXset;
      break;
    case wxCOPY:
    default:
      x_function = GXcopy;
      break;
    }

  XSetFunction (display, gc, x_function);
#ifdef wx_motif
  if (canvas && canvas->is_retained)
    XSetFunction (display, gcBacking, x_function);
#endif
  current_logical_function = function;
}

Bool wxCanvasDC:: StartDoc (char *message)
{
  return TRUE;
}

void wxCanvasDC:: EndDoc (void)
{
}

void wxCanvasDC:: StartPage (void)
{
}

void wxCanvasDC:: EndPage (void)
{
}

float wxCanvasDC:: GetCharHeight (void)
{
#ifdef wx_xview
  if (!(font && font->x_font))
    return ROUND(YDEV2LOGREL (12));

  return ROUND(YDEV2LOGREL ((int) xv_get (font->x_font, FONT_DEFAULT_CHAR_HEIGHT)));
#endif
#ifdef wx_motif
  if (!(font && font->xFont))
    return ROUND(XDEV2LOGREL (12));

  int direction, ascent, descent;
  XCharStruct overall;
  XTextExtents (font->xFont, "x", 1, &direction, &ascent,
		&descent, &overall);
  return ROUND(XDEV2LOGREL(overall.ascent + overall.descent));
#endif
}

float wxCanvasDC:: GetCharWidth (void)
{
#ifdef wx_xview
  if (!(font && font->x_font))
    return ROUND(XDEV2LOGREL (16));

  return ROUND(XDEV2LOGREL ((int) xv_get (font->x_font, FONT_DEFAULT_CHAR_WIDTH)));
#endif
#ifdef wx_motif
  if (!(font && font->xFont))
    return ROUND(XDEV2LOGREL (16));

  int direction, ascent, descent;
  XCharStruct overall;
  XTextExtents (font->xFont, "x", 1, &direction, &ascent,
		&descent, &overall);
  return ROUND(XDEV2LOGREL (overall.width));
#endif
}

void wxCanvasDC:: GetTextExtent (const char *string, float *x, float *y,
	       float *descent, float *externalLeading, wxFont *theFont)
{
  wxFont *fontToUse = theFont;
  if (!fontToUse)
    fontToUse = font;
    
#ifdef wx_motif
  if (!(fontToUse && fontToUse->xFont))
#endif
#ifdef wx_xview
    if (!(fontToUse && fontToUse->x_font))
#endif
      {
	cerr << "wxWindows warning - set a font before calling GetTextExtent!\n";
	*x = -1;
	*y = -1;
	return;
      }
#ifdef wx_motif
  XFontStruct *fontStruct = fontToUse->xFont;
#endif
#ifdef wx_xview
  XFontStruct *fontStruct = (XFontStruct *) xv_get (fontToUse->x_font, FONT_INFO);
#endif
  int direction, ascent, descent2;
  XCharStruct overall;
  XTextExtents (fontStruct, string, strlen (string), &direction, &ascent,
		&descent2, &overall);
  *x = ROUND(XDEV2LOGREL (overall.width));
  *y = ROUND(YDEV2LOGREL (ascent + descent2));
  if (descent)
    *descent = (float) descent2;
  if (externalLeading)
    *externalLeading = 0.0;
}

void wxCanvasDC:: SetMapMode (int mode)
{
  mapping_mode = mode;

  int pixel_width = 0;
  int pixel_height = 0;
  int mm_width = 0;
  int mm_height = 0;

  // First, calculate how to scale from mm to pixels.
  // Then we just need to find the scaling factor from ? to mm and multiply
  // by the first scaling factor.
#ifdef wx_xview
  Display *dpy = wxGetDisplay();
#endif
#ifdef wx_motif
  Display *dpy = NULL;
  if (wxTheApp->wx_frame)
    {
      dpy = XtDisplay (wxTheApp->wx_frame->frameShell);
    }
  else if (canvas)
    {
      dpy = XtDisplay (canvas->scrolledWindow);
    }
#endif

  int screen_no = DefaultScreen (dpy);
  pixel_width = DisplayWidth (dpy, screen_no);
  pixel_height = DisplayHeight (dpy, screen_no);
  mm_width = DisplayWidthMM (dpy, screen_no);
  mm_height = DisplayHeightMM (dpy, screen_no);

  float mm2pixelsX = pixel_width / mm_width;
  float mm2pixelsY = pixel_height / mm_height;

  switch (mode)
    {
    case MM_TWIPS:
      {
	logical_scale_x = (float) (twips2mm * mm2pixelsX);
	logical_scale_y = (float) (twips2mm * mm2pixelsY);
	break;
      }
    case MM_POINTS:
      {
	logical_scale_x = (float) (pt2mm * mm2pixelsX);
	logical_scale_y = (float) (pt2mm * mm2pixelsY);
	break;
      }
    case MM_METRIC:
      {
	logical_scale_x = mm2pixelsX;
	logical_scale_y = mm2pixelsY;
	break;
      }
    case MM_LOMETRIC:
      {
	logical_scale_x = (float) (mm2pixelsX / 10.0);
	logical_scale_y = (float) (mm2pixelsY / 10.0);
	break;
      }
    default:
    case MM_TEXT:
      {
	logical_scale_x = 1.0;
	logical_scale_y = 1.0;
	break;
      }
    }
}

void wxCanvasDC:: SetUserScale (float x, float y)
{
  user_scale_x = x;
  user_scale_y = y;

  // Force recalculation of line width
  wxPen *old_pen = current_pen;
  if (old_pen)
    {
      current_pen = NULL;
      SetPen (old_pen);
    }
}

float wxCanvasDC:: DeviceToLogicalX (int x)
{
  return XDEV2LOG (x);
}

float wxCanvasDC:: DeviceToLogicalXRel (int x)
{
  return XDEV2LOGREL (x);
}

float wxCanvasDC:: DeviceToLogicalY (int y)
{
  return YDEV2LOG (y);
}

float wxCanvasDC:: DeviceToLogicalYRel (int y)
{
  return YDEV2LOGREL (y);
}

int wxCanvasDC:: LogicalToDeviceX (float x)
{
  return XLOG2DEV (x);
}

int wxCanvasDC:: LogicalToDeviceXRel (float x)
{
  return XLOG2DEVREL (x);
}

int wxCanvasDC:: LogicalToDeviceY (float y)
{
  return YLOG2DEV (y);
}

int wxCanvasDC:: LogicalToDeviceYRel (float y)
{
  return YLOG2DEVREL (y);
}

Bool wxCanvasDC:: Blit (float xdest, float ydest, float width, float height,
      wxCanvasDC * source, float xsrc, float ysrc, int rop)
{
  // Be sure that foreground pixels (1) of
  // the Icon will be painted with pen colour. [current_pen->SetColour()]
  // Background pixels (0) will be painted with 
  // last selected background color. [::SetBackground]
  if (current_pen && autoSetting)
    SetPen (current_pen);

  if (pixmap && source->pixmap)
    {
      SetLogicalFunction (rop);
#ifdef wx_motif
      if (canvas && canvas->is_retained)
	{
	  XCopyArea (display, source->pixmap, canvas->backingPixmap, gcBacking,
		     (int) source->LogicalToDeviceX (xsrc),
                     (int) source->LogicalToDeviceY (ysrc),
                     (int) ROUND(width), (int) ROUND(height),
		     (int) XLOG2DEV_2 (xdest), (int) YLOG2DEV_2 (ydest));
/*
   XCopyPlane(display, source->pixmap, canvas->backingPixmap, gcBacking,
   (int)source->LogicalToDeviceX(xsrc), (int)source->LogicalToDeviceY(ysrc), (int)width, (int)height,
   (int)XLOG2DEV_2(xdest), (int)YLOG2DEV_2(ydest), 1);
 */
	}
#endif
      // Check if we're copying from a mono bitmap
      if (source->selected_pixmap && (source->selected_pixmap->GetDepth () == 1))
	{
	  XCopyPlane (display, source->pixmap, pixmap, gc,
		      (int) source->LogicalToDeviceX (xsrc),
                      (int) source->LogicalToDeviceY (ysrc),
                      (int) ROUND(width), (int) ROUND(height),
		      (int) XLOG2DEV (xdest), (int) YLOG2DEV (ydest), 1);
	}
      else
	{
	  XCopyArea (display, source->pixmap, pixmap, gc,
		     (int) source->LogicalToDeviceX (xsrc),
                     (int) source->LogicalToDeviceY (ysrc),
                     (int) ROUND(width), (int) ROUND(height),
		     (int) XLOG2DEV (xdest), (int) YLOG2DEV (ydest));

	}
      CalcBoundingBox (xdest, ydest);
      CalcBoundingBox (xdest + width, ydest + height);
      return TRUE;
    }
  return FALSE;
}


/*
 * Memory DC
 *
 */

IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxCanvasDC)

wxMemoryDC::wxMemoryDC (void)
{
  __type = wxTYPE_DC_MEMORY;
  display = wxGetDisplay();

  device = wxDEVICE_PIXMAP;
//  current_colour = NULL;
  current_pen_width = -1;
  current_pen_join = -1;
  current_pen_cap = -1;
  current_pen_nb_dash = -1;
  current_pen_dash = NULL;
  current_stipple = NULL;
  current_style = -1;
  current_fill = -1;

  pixmap = 0;
  pixmapWidth = 0;
  pixmapHeight = 0;
  canvas = NULL;
  clipping = FALSE;

  ok = FALSE;
  title = NULL;

  current_logical_function = -1;
  font = NULL;
  min_x = 0;
  min_y = 0;
  max_x = 0;
  max_y = 0;
  logical_origin_x = 0;
  logical_origin_y = 0;

  device_origin_x = 0;
  device_origin_y = 0;

  logical_scale_x = 1.0;
  logical_scale_y = 1.0;

  user_scale_x = 1.0;
  user_scale_y = 1.0;

  mapping_mode = MM_TEXT;

  current_pen = NULL;
  current_brush = NULL;
  current_background_brush = wxWHITE_BRUSH;
  current_text_foreground = *wxBLACK;
  current_text_background = *wxWHITE;
  current_bk_mode = wxTRANSPARENT;

  XGCValues gcvalues;
  gcvalues.foreground = BlackPixel (display,
				    DefaultScreen (display));
  gcvalues.background = WhitePixel (display,
				    DefaultScreen (display));
  gcvalues.graphics_exposures = False;
  gcvalues.line_width = 1;
  gc = XCreateGC (display, RootWindow (display, DefaultScreen (display)),
	    GCForeground | GCBackground | GCGraphicsExposures | GCLineWidth,
		  &gcvalues);

#ifdef wx_motif
  gcBacking = XCreateGC (display, RootWindow (display,
					      DefaultScreen (display)),
	    GCForeground | GCBackground | GCGraphicsExposures | GCLineWidth,
			 &gcvalues);
#endif

  background_pixel = (int) gcvalues.background;
  ok = TRUE;
//  current_colour = NULL;
  selected_pixmap = NULL;

  Colour = wxColourDisplay ();
  SetBrush (wxWHITE_BRUSH);
  SetPen (wxBLACK_PEN);
}

/*
 * Create a new dc from an old dc
 *
 */

wxMemoryDC:: wxMemoryDC (wxCanvasDC * old_dc):wxbMemoryDC (old_dc)
{
  __type = wxTYPE_DC_MEMORY;
  min_x = 0;
  min_y = 0;
  max_x = 0;
  max_y = 0;

  display = wxGetDisplay();

  device = wxDEVICE_PIXMAP;

  current_pen_width = -1;
  current_pen_join = -1;
  current_pen_cap = -1;
  current_pen_nb_dash = -1;
  current_pen_dash = NULL;
  current_stipple = NULL;
  current_style = -1;
  current_fill = -1;

  pixmap = 0;
  pixmapWidth = 0;
  pixmapHeight = 0;
  canvas = NULL;

  ok = FALSE;
  title = NULL;

  current_logical_function = -1;
  font = NULL;
  logical_origin_x = 0;
  logical_origin_y = 0;

  device_origin_x = 0;
  device_origin_y = 0;

  logical_scale_x = 1.0;
  logical_scale_y = 1.0;

  user_scale_x = 1.0;
  user_scale_y = 1.0;

  mapping_mode = MM_TEXT;

  current_pen = NULL;
  current_brush = NULL;
  current_background_brush = wxWHITE_BRUSH;
  current_text_foreground = *wxBLACK;
  current_text_background = *wxWHITE;
  current_bk_mode = wxTRANSPARENT;

  XGCValues gcvalues;
  gcvalues.foreground = BlackPixel (display,
				    DefaultScreen (display));
  gcvalues.background = WhitePixel (display,
				    DefaultScreen (display));
  gcvalues.graphics_exposures = False;
  gcvalues.line_width = 1;
  gc = XCreateGC (display, RootWindow (display, DefaultScreen (display)),
	    GCForeground | GCBackground | GCGraphicsExposures | GCLineWidth,
		  &gcvalues);

#ifdef wx_motif
  gcBacking = XCreateGC (display, RootWindow (display,
					      DefaultScreen (display)),
	    GCForeground | GCBackground | GCGraphicsExposures | GCLineWidth,
			 &gcvalues);
#endif

  background_pixel = (int) gcvalues.background;
  ok = TRUE;
//  current_colour = NULL;
  selected_pixmap = NULL;

  Colour = wxColourDisplay ();
  SetBrush (wxWHITE_BRUSH);
  SetPen (wxBLACK_PEN);
}

wxMemoryDC::~wxMemoryDC (void)
{
}

void wxMemoryDC:: SelectObject (wxBitmap * bitmap)
{
  if (gc)
    XFreeGC(display, gc);
  gc = NULL;

  if (!bitmap)
  {
    selected_pixmap = NULL;
    pixmap = 0;
    pixmapWidth = 0;
    pixmapHeight = 0;
    return;
  }
  
  selected_pixmap = bitmap;
  pixmap = bitmap->x_pixmap;
  pixmapWidth = bitmap->GetWidth ();
  pixmapHeight = bitmap->GetHeight ();

  XGCValues gcvalues;
  gcvalues.foreground = BlackPixel (display,
				    DefaultScreen (display));
  gcvalues.background = WhitePixel (display,
				    DefaultScreen (display));
  gcvalues.graphics_exposures = False;
  gcvalues.line_width = 1;
  gc = XCreateGC (display, pixmap,
	    GCForeground | GCBackground | GCGraphicsExposures | GCLineWidth,
		  &gcvalues);
}

void wxMemoryDC::GetSize(float *w, float *h)
{
  *w = pixmapWidth;
  *h = pixmapHeight;
}


/****** Utility function for wxItem/wxPanel ***********/

#ifdef wx_motif
XColor itemColors[5];
int 
wxComputeColors (wxColour * back, wxColour * fore)
#else
int 
wxComputeColors (wxColour *, wxColour *)
#endif
{
  int result;
#ifdef wx_motif
  static XmColorProc colorProc;
#endif

  result = wxNO_COLORS;
#ifdef wx_motif
  if (back)
    {
      itemColors[0].red = (((long) back->Red ()) << 8);
      itemColors[0].green = (((long) back->Green ()) << 8);
      itemColors[0].blue = (((long) back->Blue ()) << 8);
      itemColors[0].flags = DoRed | DoGreen | DoBlue;
      if (colorProc == (XmColorProc) NULL)
	{
	  // Get a ptr to the actual function
	  colorProc = XmSetColorCalculation ((XmColorProc) NULL);
	  // And set it back to motif.
	  XmSetColorCalculation (colorProc);
	}
      (*colorProc) (&itemColors[wxBACK_INDEX],
		    &itemColors[wxFORE_INDEX],
		    &itemColors[wxSELE_INDEX],
		    &itemColors[wxTOPS_INDEX],
		    &itemColors[wxBOTS_INDEX]);
      result = wxBACK_COLORS;
    }
  if (fore)
    {
      itemColors[wxFORE_INDEX].red = (((long) fore->Red ()) << 8);
      itemColors[wxFORE_INDEX].green = (((long) fore->Green ()) << 8);
      itemColors[wxFORE_INDEX].blue = (((long) fore->Blue ()) << 8);
      itemColors[wxFORE_INDEX].flags = DoRed | DoGreen | DoBlue;
      if (result == wxNO_COLORS)
	result = wxFORE_COLORS;
    }

  Colormap cmap = wxMainColormap;
  Display *dpy = XtDisplay (wxTheApp->topLevel);

  if (back)
    {
      /* 5 Colours to allocate */
      for (int i = 0; i < 5; i++)
	if (!YAllocColor (dpy, cmap, &itemColors[i]))
	  result = wxNO_COLORS;
    }
  else if (fore)
    {
      /* Only 1 colour to allocate */
      if (!YAllocColor (dpy, cmap, &itemColors[wxFORE_INDEX]))
	result = wxNO_COLORS;
    }
#endif

  return (result);

}

/*
 * Panel device context
 *
 */

IMPLEMENT_DYNAMIC_CLASS(wxPanelDC, wxCanvasDC)

// Default constructor
wxPanelDC::wxPanelDC (void)
{
  __type = wxTYPE_DC_PANEL;
  panel = NULL;
  device = wxDEVICE_PANEL;
}

wxPanelDC:: wxPanelDC (wxPanel * the_panel) :
            wxbPanelDC (the_panel)
{
  panel = the_panel;
  device = wxDEVICE_PANEL;
}

wxPanelDC::~wxPanelDC (void)
{
}

/*
 * Screen device context
 */

IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxCanvasDC)

wxScreenDC::wxScreenDC(void)
{
  display = wxGetDisplay();
  pixmap = RootWindow(display, DefaultScreen(display));
}

wxScreenDC::~wxScreenDC(void)
{
}

