shithub: freetype+ttf2subf

Download patch

ref: cb58dbb4fbfa61c2b361daa05c48397dd8c7ead0
parent: 14954e6bc2186ae7ad03766006fcfe058b3b752d
author: David Turner <[email protected]>
date: Mon Jan 17 06:04:55 EST 2000

Some important changes were performed :

- the graphics drivers were moved from "demos/config/*" to
  "demos/graph/*"

- a Win32 graphics driver was added. (note that keyboard
  management is a bit buggy, but it's really usable).

- the "demos/Makefile" and "demos/graph/rules.mk" were
  seriously modified

- the demo programs now compile AND run with gcc,
  Visual C++ and LCC-Win32 !! The other ones should be
  really easy to add now, as LCC was the really smart ass
  in this list...

git/fs: mount .git/fs: mount/attach disallowed
--- a/demos/graph/gpm_os2.def
+++ /dev/null
@@ -1,5 +1,0 @@
-NAME        WINDOWCOMPAT
-
-DESCRIPTION 'FreeType Graphics'
-HEAPSIZE    8192
-STACKSIZE   40888
--- a/demos/graph/grdevice.c
+++ b/demos/graph/grdevice.c
@@ -1,6 +1,7 @@
 #include "grobjs.h"
 #include "grdevice.h"
 #include <stdlib.h>
+#include <string.h>
 
   grDeviceChain   gr_device_chain[ GR_MAX_DEVICES ];
   int             gr_num_devices = 0;
--- a/demos/graph/grfont.c
+++ b/demos/graph/grfont.c
@@ -1,4 +1,5 @@
 #include "grfont.h"
+#include <string.h>
 
   /* font characters */
 
@@ -329,11 +330,14 @@
   {
     if (string)
     {
+	  grColor color;
+
+	  color.value = 127;
       grWriteCellString( gr_text_bitmap,
                          gr_margin_right + (gr_cursor_x << 3),
                          gr_margin_top   + (gr_cursor_y << 3),
                          string,
-                         (grColor)127L );
+                         color );
  
       gr_cursor_x += strlen(string);
     }
--- a/demos/graph/grinit.c
+++ b/demos/graph/grinit.c
@@ -13,6 +13,9 @@
 #include "gros2pm.h"
 #endif
 
+#ifdef DEVICE_WIN32
+#include "grwin32.h"
+#endif
 
 
  /**********************************************************************
--- a/demos/graph/grobjs.c
+++ b/demos/graph/grobjs.c
@@ -1,6 +1,6 @@
 #include "grobjs.h"
 #include <stdlib.h>
-
+#include <memory.h>
 
   int  grError = 0;
 
--- a/demos/graph/gros2pm.c
+++ /dev/null
@@ -1,895 +1,0 @@
-#include "gros2pm.h"
-
-
-#define INCL_DOS
-#define INCL_WIN
-#define INCL_GPI
-#define INCL_SUB
-
-#include <os2.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-
-  static void Panic( const char* message )
-  {
-    fprintf( stderr, "%s", message );
-    exit(1);
-  }
-
-  typedef struct Translator
-  {
-    ULONG   os2key;
-    grKey   grkey;
-    
-  } Translator;
-  
-
-  static
-  Translator  key_translators[] =
-  {
-    { VK_BACKSPACE, grKeyBackSpace },
-    { VK_TAB,       grKeyTab       },
-    { VK_ENTER,     grKeyReturn    },
-    { VK_ESC,       grKeyEsc       },
-    { VK_HOME,      grKeyHome      },
-    { VK_LEFT,      grKeyLeft      },
-    { VK_UP,        grKeyUp        },
-    { VK_RIGHT,     grKeyRight     },
-    { VK_DOWN,      grKeyDown      },
-    { VK_PAGEUP,    grKeyPageUp    },
-    { VK_PAGEDOWN,  grKeyPageDown  },
-    { VK_END,       grKeyEnd       },
-    { VK_F1,        grKeyF1        },
-    { VK_F2,        grKeyF2        },
-    { VK_F3,        grKeyF3        },
-    { VK_F4,        grKeyF4        },
-    { VK_F5,        grKeyF5        },
-    { VK_F6,        grKeyF6        },
-    { VK_F7,        grKeyF7        },
-    { VK_F8,        grKeyF8        },
-    { VK_F9,        grKeyF9        },
-    { VK_F10,       grKeyF10       },
-    { VK_F11,       grKeyF11       },
-    { VK_F12,       grKeyF12       }
-  };
-
-
-#define MAX_PIXEL_MODES  32
-
-  static int           num_pixel_modes = 0;
-  static grPixelMode   pixel_modes[ MAX_PIXEL_MODES ];  
-  static int           pixel_depth[ MAX_PIXEL_MODES ];
-
-  static  HAB   gr_anchor;   /* device anchor block */
-
-  typedef POINTL  PMBlitPoints[4];
-
-
-  typedef struct grPMSurface_
-  {
-    grSurface  root;
-    grBitmap   image;
-
-    HAB        anchor;         /* handle to anchor block for surface's window */
-    HWND       frame_window;   /* handle to window's frame                    */
-    HWND       client_window;  /* handle to window's client                   */
-    HWND       title_window;   /* handle to window's title bar                */
-
-    HPS        image_ps;       /* memory presentation space used to hold */
-                               /* the surface's content under PM         */
-    HDC        image_dc;       /* memory device context for the image    */
-
-    HEV        event_lock;     /* semaphore used in listen_surface   */
-    HMTX       image_lock;     /* a mutex used to synchronise access */
-                               /* to the memory presentation space   */
-                               /* used to hold the surface           */
-
-    TID        message_thread; /* thread used to process this surface's */
-                               /* messages..                            */
-
-    PBITMAPINFO2 bitmap_header;/* os/2 bitmap descriptor                   */
-    HBITMAP      os2_bitmap;   /* Handle to OS/2 bitmap contained in image */
-    BOOL         ready;        /* ??? */
-
-    long         shades[256];  /* indices of gray levels in pixel_mode_gray */
-
-    POINTL       surface_blit[4];  /* surface blitting table   */
-    POINTL       magnify_blit[4];  /* magnifier blitting table */
-    int          magnification;    /* level of magnification   */
-    POINTL       magnify_center;
-    SIZEL        magnify_size;
-
-    grEvent      event;
-
-    PMBlitPoints blit_points;
-
-  } grPMSurface;
-
-
-
-  static
-  void  enable_os2_iostreams( void )
-  {
-    PTIB  thread_block;
-    PPIB  process_block;
-
-    /* XXX : This is a very nasty hack, it fools OS/2 and let the program */
-    /*       call PM functions, even though stdin/stdout/stderr are still */
-    /*       directed to the standard i/o streams..                       */
-    /*       The program must be compiled with WINDOWCOMPAT               */
-    /*                                                                    */
-    /*   Credits go to Michal for finding this !!                         */
-    /*                                                                    */
-    DosGetInfoBlocks( &thread_block, &process_block );
-    process_block->pib_ultype = 3;
-  }
-
-
-
-  static
-  int  init_device( void )
-  {
-    enable_os2_iostreams();
-
-    /* create an anchor block. This will allow this thread (i.e. the */
-    /* main one) to call Gpi functions..                             */
-    gr_anchor = WinInitialize(0);
-    if (!gr_anchor)
-    {
-      /* could not initialise Presentation Manager */
-      return -1;
-    }
-
-    return 0;
-  }
-
-
-
-  static
-  void  done_device( void )
-  {
-    /* Indicates that we do not use the Presentation Manager, this */
-    /* will also release all associated resources..                */
-    WinTerminate( gr_anchor );
-  }
-
-
-
-  /* close a given window */
-  static
-  void  done_surface( grPMSurface*  surface )
-  {
-    if ( surface->frame_window )
-      WinDestroyWindow( surface->frame_window );
-
-    WinReleasePS( surface->image_ps );
-
-    grDoneBitmap( &surface->image );
-    grDoneBitmap( &surface->root.bitmap );
-  }
-
-
-
-
-
-  static
-  void add_pixel_mode( grPixelMode  pixel_mode,
-                       int          depth )
-  {
-    if ( num_pixel_modes >= MAX_PIXEL_MODES )
-      Panic( "X11.Too many pixel modes\n" );
-      
-    pixel_modes[ num_pixel_modes ] = pixel_mode;
-    pixel_depth[ num_pixel_modes ] = depth;
-    
-    num_pixel_modes++;
-  }
-
-
-#define LOCK(x)    DosRequestMutexSem( x, SEM_INDEFINITE_WAIT );
-#define UNLOCK(x)  DosReleaseMutexSem( x )
-
-
-  static
-  const int  pixel_mode_bit_count[] =
-  {
-    0,
-    1,
-    4,
-    8,   /* pal8 */
-    8,   /* gray */
-    15,
-    16,
-    24,
-    32
-  };
-
-
- /************************************************************************
-  *
-  * Technical note : how the OS/2 Presntation Manager driver works
-  *
-  * PM is, in my opinion, a bloated and over-engineered graphics
-  * sub-system, even though it has lots of nice features. Here are
-  * a few tidbits about it :
-  *
-  *
-  * - under PM, a "bitmap" is a device-specific object whose bits are
-  *   not directly accessible to the client application. This means
-  *   that we must use a scheme like the following to display our
-  *   surfaces :
-  *
-  *     - hold, for each surface, its own bitmap buffer where the
-  *       rest of MiGS writes directly.
-  *
-  *     - create a PM bitmap object with the same dimensions (and
-  *       possibly format).
-  *
-  *     - copy the content of each updated rectangle into the
-  *       PM bitmap with the function 'GpiSetBitmapBits'.
-  *
-  *     - finally, "blit" the PM bitmap to the screen calling
-  *       'GpiBlitBlt'
-  *
-  * - but there is more : you cannot directly blit a PM bitmap to the
-  *   screen with PM. The 'GpiBlitBlt' only works with presentation
-  *   spaces. This means that we also need to create, for each surface :
-  *
-  *     - a memory presentation space, used to hold the PM bitmap
-  *     - a "memory device context" for the presentation space
-  *
-  *   The blit is then performed from the memory presentation space
-  *   to the screen's presentation space..
-  *
-  *
-  * - because each surface creates its own event-handling thread,
-  *   we must protect the surface's presentation space from concurrent
-  *   accesses (i.e. calls to 'GpiSetBitmapBits' when drawing to the
-  *   surface, and calls to 'GpiBlitBlt' when drawing it on the screen
-  *   are performed in two different threads).
-  *
-  *   we use a simple mutex to do this.
-  *
-  *
-  * - we also use a semaphore to perform a rendez-vous between the
-  *   main and event-handling threads (needed in "listen_event").
-  *
-  ************************************************************************/
-
-  static
-  void  RunPMWindow( grPMSurface*  surface );
-
-
-
-
-
-
-
-
-
-
-
-
-  static
-  void  convert_gray_to_pal8( grPMSurface* surface,
-                              int          x,
-                              int          y,
-                              int          w,
-                              int          h )
-  {
-    grBitmap*  target  = &surface->image;
-    grBitmap*  source  = &surface->root.bitmap;
-    byte*      write   = (byte*)target->buffer + y*target->pitch + x;
-    byte*      read    = (byte*)source->buffer + y*source->pitch + x;
-    long*      palette = surface->shades;
-    
-    while (h > 0)
-    {
-      byte*  _write = write;
-      byte*  _read  = read;
-      byte*  limit  = _write + w;
-      
-      for ( ; _write < limit; _write++, _read++ )
-        *_write = (byte) palette[ *_read ];
-
-      write += target->pitch;
-      read  += source->pitch;
-      h--;
-    }
-  }
-
-
-  static
-  void  convert_gray_to_16( grPMSurface* surface,
-                            int          x,
-                            int          y,
-                            int          w,
-                            int          h )
-  {
-    grBitmap*  target  = &surface->image;
-    grBitmap*  source  = &surface->root.bitmap;
-    byte*      write   = (byte*)target->buffer + y*target->pitch + 2*x;
-    byte*      read    = (byte*)source->buffer + y*source->pitch + x;
-    long*           palette = surface->shades;
-    
-    while (h > 0)
-    {
-      byte*  _write = write;
-      byte*  _read  = read;
-      byte*  limit  = _write + 2*w;
-      
-      for ( ; _write < limit; _write += 2, _read++ )
-        *(short*)_write = (short)palette[ *_read ];
-
-      write += target->pitch;
-      read  += source->pitch;
-      h--;
-    }
-  }
-
-
-  static
-  void  convert_gray_to_24( grPMSurface* surface,
-                            int          x,
-                            int          y,
-                            int          w,
-                            int          h )
-  {
-    grBitmap*  target  = &surface->image;
-    grBitmap*  source  = &surface->root.bitmap;
-    byte*      write   = (byte*)target->buffer + y*target->pitch + 3*x;
-    byte*      read    = (byte*)source->buffer + y*source->pitch + x;
-    
-    while (h > 0)
-    {
-      byte*  _write = write;
-      byte*  _read  = read;
-      byte*  limit  = _write + 3*w;
-      
-      for ( ; _write < limit; _write += 3, _read++ )
-      {
-        byte  color = *_read;
-        
-        _write[0] =
-        _write[1] =
-        _write[2] = color;
-      }
-
-      write += target->pitch;
-      read  += source->pitch;
-      h--;
-    }
-  }
-
-
-  static
-  void  convert_gray_to_32( grPMSurface* surface,
-                            int          x,
-                            int          y,
-                            int          w,
-                            int          h )
-  {
-    grBitmap*  target  = &surface->image;
-    grBitmap*  source  = &surface->root.bitmap;
-    byte*      write   = (byte*)target->buffer + y*target->pitch + 4*x;
-    byte*      read    = (byte*)source->buffer + y*source->pitch + x;
-    
-    while (h > 0)
-    {
-      byte*  _write = write;
-      byte*  _read  = read;
-      byte*  limit  = _write + 4*w;
-      
-      for ( ; _write < limit; _write += 4, _read++ )
-      {
-        byte  color = *_read;
-        
-        _write[0] =
-        _write[1] =
-        _write[2] =
-        _write[3] = color;
-      }
-
-      write += target->pitch;
-      read  += source->pitch;
-      h--;
-    }
-  }
-
-
-  static
-  void  convert_rectangle( grPMSurface* surface,
-                           int          x,
-                           int          y,
-                           int          w,
-                           int          h )
-  {
-    int  z;
-    
-    /* first of all, clip to the surface's area */
-    if ( x   >= surface->image.width ||
-         x+w <= 0                    ||
-         y   >= surface->image.rows  ||
-         y+h <= 0 )
-      return;
- 
-    if ( x < 0 )
-    {
-      w += x;
-      x  = 0;
-    }
- 
-    z = (x + w) - surface->image.width;
-    if (z > 0)
-      w -= z;
-      
-    z = (y + h) - surface->image.rows;
-    if (z > 0)
-      h -= z;
-      
-    /* convert the rectangle to the target depth for gray surfaces */
-    if (surface->root.bitmap.mode == gr_pixel_mode_gray)
-    {
-      switch (surface->image.mode)
-      {
-        case gr_pixel_mode_pal8  :
-          convert_gray_to_pal8( surface, x, y, w, h );
-          break;
-
-        case gr_pixel_mode_rgb555:
-        case gr_pixel_mode_rgb565:
-          convert_gray_to_16  ( surface, x, y, w, h );
-          break;
-
-        case gr_pixel_mode_rgb24:
-          convert_gray_to_24  ( surface, x, y, w, h );
-          break;
-
-        case gr_pixel_mode_rgb32:
-          convert_gray_to_32  ( surface, x, y, w, h );
-          break;
-
-        default:
-          ;
-      }
-    }
-  } 
-
-
-  static
-  void  refresh_rectangle( grPMSurface* surface,
-                           int          x,
-                           int          y,
-                           int          w,
-                           int          h )
-  {
-    convert_rectangle( surface, x, y, w, h );
-
-    WinInvalidateRect( surface->client_window, NULL, FALSE );
-    WinUpdateWindow( surface->frame_window );
-  }
-
-  
-  static
-  void  set_title( grPMSurface* surface,
-                   const char*  title )
-  {
-    WinSetWindowText( surface->title_window, (PSZ)title );
-  }
-
-
-
-  static  
-  void  listen_event( grPMSurface* surface,
-                      int          event_mask,
-                      grEvent*     grevent )
-  {
-    ULONG  ulRequestCount;
-
-    (void) event_mask;   /* ignored for now */
-
-    /* the listen_event function blocks until there is an event to process */
-    DosWaitEventSem( surface->event_lock, SEM_INDEFINITE_WAIT );
-    DosQueryEventSem( surface->event_lock, &ulRequestCount );
-    *grevent = surface->event;
-    DosResetEventSem( surface->event_lock, &ulRequestCount );
-
-    return;
-  }
-
-
-  static
-  int  init_surface( grPMSurface*  surface,
-                     grBitmap*     bitmap )
-  {
-    PBITMAPINFO2  bit;
-    SIZEL         sizl = { 0, 0 };
-    LONG          palette[256];
-
-    /* create the bitmap - under OS/2, we support all modes as PM */
-    /* handles all conversions automatically..                    */
-    if ( grNewBitmap( surface->root.bitmap.mode,
-                      surface->root.bitmap.grays,
-                      surface->root.bitmap.width,
-                      surface->root.bitmap.rows,
-                      bitmap ) )
-      return grError;
-
-    surface->root.bitmap = *bitmap;
-
-    /* create the image and event lock */
-    DosCreateEventSem( NULL, &surface->event_lock, 0, TRUE  );
-    DosCreateMutexSem( NULL, &surface->image_lock, 0, FALSE );
-
-    /* create the image's presentation space */
-    surface->image_dc = DevOpenDC( gr_anchor,
-                                   OD_MEMORY, (PSZ)"*", 0L, 0L, 0L );
-
-    surface->image_ps = GpiCreatePS( gr_anchor,
-                                     surface->image_dc,
-                                     &sizl,
-                                     PU_PELS    | GPIT_MICRO |
-                                     GPIA_ASSOC | GPIF_DEFAULT );
-
-    GpiSetBackMix( surface->image_ps, BM_OVERPAINT );
-
-    /* create the image's PM bitmap */
-    bit = (PBITMAPINFO2)grAlloc( sizeof(BITMAPINFO2) + 256*sizeof(RGB2) );
-    surface->bitmap_header = bit;
-
-    bit->cbFix   = sizeof( BITMAPINFOHEADER2 );
-    bit->cx      = surface->root.bitmap.width;
-    bit->cy      = surface->root.bitmap.rows;
-    bit->cPlanes = 1;
-
-    bit->argbColor[0].bBlue  = 0;
-    bit->argbColor[0].bGreen = 0;
-    bit->argbColor[0].bRed   = 0;
-
-    bit->argbColor[1].bBlue  = 255;
-    bit->argbColor[1].bGreen = 255;
-    bit->argbColor[1].bRed   = 255;
-
-    bit->cBitCount = pixel_mode_bit_count[ surface->root.bitmap.mode ];
-
-    surface->os2_bitmap = GpiCreateBitmap( surface->image_ps,
-                                           (PBITMAPINFOHEADER2)bit,
-                                           0L, NULL, NULL );
-
-    GpiSetBitmap( surface->image_ps, surface->os2_bitmap );
-
-    bit->cbFix = sizeof( BITMAPINFOHEADER2 );
-    GpiQueryBitmapInfoHeader( surface->os2_bitmap,
-                              (PBITMAPINFOHEADER2)bit );
-
-    /* for gr_pixel_mode_gray, create a gray-levels logical palette */
-    if ( bitmap->mode == gr_pixel_mode_gray )
-    {
-      int     x, count;
-
-      count = bitmap->grays;
-      for ( x = 0; x < count; x++ )
-        palette[x] = (((count-x)*255)/count) * 0x010101;
-
-      /* create logical color table */
-      GpiCreateLogColorTable( surface->image_ps,
-                              (ULONG) LCOL_PURECOLOR,
-                              (LONG)  LCOLF_CONSECRGB,
-                              (LONG)  0L,
-                              (LONG)  count,
-                              (PLONG) palette );
-
-      /* now, copy the color indexes to surface->shades */
-      for ( x = 0; x < count; x++ )
-        surface->shades[x] = GpiQueryColorIndex( surface->image_ps,
-                                                 0, palette[x] );
-    }
-
-    /* set up the blit points array */
-    surface->blit_points[1].x = surface->root.bitmap.width;
-    surface->blit_points[1].y = surface->root.bitmap.rows;
-    surface->blit_points[3]   = surface->blit_points[1];
-
-    /* Finally, create the event handling thread for the surface's window */
-    DosCreateThread( &surface->message_thread,
-                     (PFNTHREAD) RunPMWindow,
-                     (ULONG)     surface,
-                     0UL,
-                     32920 );
-
-    surface->root.done         = (grDoneSurfaceFunc) done_surface;
-    surface->root.refresh_rect = (grRefreshRectFunc) refresh_rectangle;
-    surface->root.set_title    = (grSetTitleFunc)    set_title;
-    surface->root.listen_event = (grListenEventFunc) listen_event;
-    
-    convert_rectangle( surface, 0, 0, bitmap->width, bitmap->rows );
-    return 0;
-  }
-
-
-
-  MRESULT EXPENTRY  Message_Process( HWND    handle,
-                                     ULONG   mess,
-                                     MPARAM  parm1,
-                                     MPARAM  parm2 );
-
-
-  static
-  void  RunPMWindow( grPMSurface*  surface )
-  {
-    unsigned char   class_name[] = "DisplayClass";
-             ULONG  class_flags;
-
-    static   HMQ    queue;
-             QMSG   message;
-
-    /* create an anchor to allow this thread to use PM */
-    surface->anchor = WinInitialize(0);
-    if (!surface->anchor)
-    {
-      printf( "Error doing WinInitialize()\n" );
-      return;
-    }
-
-    /* create a message queue */
-    queue = WinCreateMsgQueue( surface->anchor, 0 );
-    if (!queue)
-    {
-      printf( "Error doing >inCreateMsgQueue()\n" );
-      return;
-    }
-
-    /* register the window class */
-    if ( !WinRegisterClass( surface->anchor,
-                            (PSZ)   class_name,
-                            (PFNWP) Message_Process,
-                            CS_SIZEREDRAW,
-                            0 ) )
-    {
-      printf( "Error doing WinRegisterClass()\n" );
-      return;
-    }
-
-    /* create the PM window */
-    class_flags = FCF_TITLEBAR | FCF_MINBUTTON | FCF_DLGBORDER | 
-                  FCF_TASKLIST | FCF_SYSMENU; 
-
-    surface->frame_window = WinCreateStdWindow(
-                                HWND_DESKTOP,
-                                WS_VISIBLE,
-                                &class_flags,
-                                (PSZ) class_name,
-                                (PSZ) "FreeType PM Graphics",
-                                WS_VISIBLE,
-                                0, 0,
-                                &surface->client_window );
-    if (!surface->frame_window)
-    {
-      printf( "Error doing WinCreateStdWindow()\n" );
-      return;
-    }
-
-    /* find the title window handle */
-    surface->title_window = WinWindowFromID( surface->frame_window,
-                                             FID_TITLEBAR );
-
-    /* set Window size and position */
-    WinSetWindowPos( surface->frame_window,
-                     0L,
-                     (SHORT) 60,
-                     (SHORT) WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN ) -
-                             surface->root.bitmap.rows + 100,
-
-                     (SHORT) WinQuerySysValue( HWND_DESKTOP, SV_CYDLGFRAME )*2 +
-                             surface->root.bitmap.width,
-
-                     (SHORT) WinQuerySysValue( HWND_DESKTOP, SV_CYTITLEBAR ) +
-                             WinQuerySysValue( HWND_DESKTOP, SV_CYDLGFRAME )*2 +
-                             surface->root.bitmap.rows,
-
-                     SWP_SIZE | SWP_MOVE );
-
-    /* save the handle to the current surface within the window words */
-    WinSetWindowPtr( surface->frame_window,QWL_USER, surface );
-
-    /* run the message queue till the end */
-    while ( WinGetMsg( surface->anchor, &message, (HWND)NULL, 0, 0 ) )
-      WinDispatchMsg( surface->anchor, &message );
-
-    /* clean-up */
-    WinDestroyWindow( surface->frame_window );
-    surface->frame_window = 0;
-
-    WinDestroyMsgQueue( queue );
-    WinTerminate( surface->anchor );
-
-    /* await death... */
-    while ( 1 )
-      DosSleep( 100 );
-  }
-
-
-
-
-  /* Message processing for our PM Window class */
-  MRESULT EXPENTRY  Message_Process( HWND    handle,
-                                     ULONG   mess,
-                                     MPARAM  parm1,
-                                     MPARAM  parm2 )
-  {
-     static HDC     screen_dc;
-     static HPS     screen_ps;
-     static BOOL    minimized;
-
-     SIZEL   sizl;
-     SWP     swp;
-
-     grPMSurface*  surface;
-
-    /* get the handle to the window's surface */
-    surface = (grPMSurface*)WinQueryWindowPtr( handle, QWL_USER );
-
-    switch( mess )
-    {
-    case WM_DESTROY:
-      /* warn the main thread to quit if it didn't know */
-      surface->event.type = gr_event_key;
-      surface->event.key  = grKeyEsc;
-      DosPostEventSem( surface->event_lock );
-      break;
-
-    case WM_CREATE:
-      /* set original magnification */
-      minimized = FALSE;
-
-      /* create Device Context and Presentation Space for screen. */
-      screen_dc = WinOpenWindowDC( handle );
-      screen_ps = GpiCreatePS( surface->anchor,
-                               screen_dc,
-                               &sizl,
-                               PU_PELS | GPIT_MICRO |
-                               GPIA_ASSOC | GPIF_DEFAULT );
-
-      /* take the input focus */
-      WinFocusChange( HWND_DESKTOP, handle, 0L );
-      break;
-
-    case WM_MINMAXFRAME:
-      /* to update minimized if changed */
-      swp = *((PSWP) parm1);
-      if ( swp.fl & SWP_MINIMIZE ) 
-        minimized = TRUE;
-      if ( swp.fl & SWP_RESTORE )
-        minimized = FALSE;
-      return WinDefWindowProc( handle, mess, parm1, parm2 );
-      break;
-
-    case WM_ERASEBACKGROUND:
-    case WM_PAINT:  
-      /* copy the memory image of the screen out to the real screen */
-      DosRequestMutexSem( surface->image_lock, SEM_INDEFINITE_WAIT );
-      WinBeginPaint( handle, screen_ps, NULL );
-      
-      /* main image and magnified picture */
-      GpiBitBlt( screen_ps,
-                 surface->image_ps,
-                 4L,
-                 surface->blit_points,
-                 ROP_SRCCOPY, BBO_AND );
-
-      WinEndPaint( screen_ps );
-      DosReleaseMutexSem( surface->image_lock );   
-      break;
-
-    case WM_CHAR:
-      if ( CHARMSG( &mess )->fs & KC_KEYUP )
-        break;
-
-      /* look for a specific vkey */
-      {
-        int          count = sizeof( key_translators )/sizeof( key_translators[0] );
-        Translator*  trans = key_translators;
-        Translator*  limit = trans + count;
-
-        for ( ; trans < limit; trans++ )
-          if ( CHARMSG(&mess)->vkey == trans->os2key )
-          {
-            surface->event.key = trans->grkey;
-            goto Do_Key_Event;
-          }
-      }
-
-      /* otherwise, simply record the character code */
-      if ( (CHARMSG( &mess )->fs & KC_CHAR) == 0 )
-        break;
-
-      surface->event.key = CHARMSG(&mess)->chr;
-
-    Do_Key_Event:
-      surface->event.type = gr_event_key;
-      DosPostEventSem( surface->event_lock );
-      break;
-
-    default:
-      return WinDefWindowProc( handle, mess, parm1, parm2 );
-    }
-
-    return (MRESULT) FALSE;
-  }
-
-
-
-
-
-
-
-#if 0
-  static
-  grKey  KeySymTogrKey(   key )
-  {
-    grKey        k;
-    int          count = sizeof(key_translators)/sizeof(key_translators[0]);
-    Translator*  trans = key_translators;
-    Translator*  limit = trans + count;
-
-    k = grKeyNone;
-
-    while ( trans < limit )
-    {
-      if ( trans->xkey == key )
-      {
-        k = trans->grkey;
-        break;
-      }
-      trans++;
-    }
-
-    return k;
-  }
-
-
-
-  static  
-  void  listen_event( grPMSurface* surface,
-                      int          event_mask,
-                      grEvent*     grevent )
-  {
-    grKey           grkey;
-
-    /* XXXX : For now, ignore the event mask, and only exit when */
-    /*        a key is pressed..                                 */
-    (void)event_mask;
-
-
-    /* Now, translate the keypress to a grKey */
-    /* If this wasn't part of the simple translated keys, simply get the charcode */
-    /* from the character buffer                                                  */
-    grkey = grKEY(key_buffer[key_cursor++]);
-      
-  Set_Key:
-    grevent->type = gr_key_down;
-    grevent->key  = grkey;
-  }
-
-#endif
-
-
-
-  grDevice  gr_os2pm_device =
-  {
-    sizeof( grPMSurface ),
-    "os2pm",
-    
-    init_device,
-    done_device,
-    
-    (grDeviceInitSurfaceFunc) init_surface,
-    
-    0,
-    0
-    
-  };
-
-
--- a/demos/graph/gros2pm.h
+++ /dev/null
@@ -1,23 +1,0 @@
-#ifndef GROS2PM_H
-#define GROS2PM_H
-
-#include "grobjs.h"
-
-  extern
-  grDevice  gr_os2pm_device;
-
-#ifdef GR_INIT_BUILD
-  static
-  grDeviceChain  gr_os2pm_device_chain =
-  {
-    "os2pm",
-    &gr_os2pm_device,
-    GR_INIT_DEVICE_CHAIN
-  };
-
-#undef GR_INIT_DEVICE_CHAIN
-#define GR_INIT_DEVICE_CHAIN  &gr_os2pm_device_chain
-
-#endif  /* GR_INIT_BUILD */
-
-#endif /* GROS2PM_H */
--- a/demos/graph/grx11.c
+++ /dev/null
@@ -1,936 +1,0 @@
-#include "grx11.h"
-
-
-#ifdef TEST
-#include "grfont.h"
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/cursorfont.h>
-#include <X11/keysym.h>
-
-  static void Panic( const char* message )
-  {
-    fprintf( stderr, "%s", message );
-    exit(1);
-  }
-
-  typedef struct Translator
-  {
-    KeySym  xkey;
-    grKey   grkey;
-    
-  } Translator;
-  
-  static
-  Translator  key_translators[] =
-  {
-    { XK_BackSpace, grKeyBackSpace },
-    { XK_Tab,       grKeyTab       },
-    { XK_Return,    grKeyReturn    },
-    { XK_Escape,    grKeyEsc       },
-    { XK_Home,      grKeyHome      },
-    { XK_Left,      grKeyLeft      },
-    { XK_Up,        grKeyUp        },
-    { XK_Right,     grKeyRight     },
-    { XK_Down,      grKeyDown      },
-    { XK_Page_Up,   grKeyPageUp    },
-    { XK_Page_Down, grKeyPageDown  },
-    { XK_End,       grKeyEnd       },
-    { XK_Begin,     grKeyHome      },
-    { XK_F1,        grKeyF1        },
-    { XK_F2,        grKeyF2        },
-    { XK_F3,        grKeyF3        },
-    { XK_F4,        grKeyF4        },
-    { XK_F5,        grKeyF5        },
-    { XK_F6,        grKeyF6        },
-    { XK_F7,        grKeyF7        },
-    { XK_F8,        grKeyF8        },
-    { XK_F9,        grKeyF9        },
-    { XK_F10,       grKeyF10       },
-    { XK_F11,       grKeyF11       },
-    { XK_F12,       grKeyF12       }
-  };
-
-
-#ifdef TEST
-  
-#define grAlloc  malloc
-  
-#endif
-
-
-  static Display*  display;
-  static char*     displayname = "";
-
-  static Cursor  idle;
-  static Cursor  busy;
-
-#define MAX_PIXEL_MODES  32
-
-  typedef XPixmapFormatValues  XDepth;
-
-  static int           num_pixel_modes = 0;
-  static grPixelMode   pixel_modes[ MAX_PIXEL_MODES ];  
-  static XDepth        pixel_depth[ MAX_PIXEL_MODES ];
-
-  typedef struct grXSurface_
-  {
-    grSurface      root;
-    grBitmap       image;
-
-    Window         win;
-    Visual*        visual;
-    Colormap       colormap;
-    int            depth;
-    Bool           gray;
-    
-    GC             gc;
-    
-    XColor         color[256];   /* gray levels palette for 8-bit modes */
-    XImage*        ximage;
-
-    int            win_org_x;
-    int            win_org_y;
-    int            win_width;
-    int            win_height;
-    
-    int            image_width;
-    int            image_height;
-    
-  } grXSurface;
-
-
-
-
-  /* close a given window */
-  static
-  void  done_surface( grXSurface*  surface )
-  {
-    XUnmapWindow( display, surface->win );
-  }
-
-
-
-  /* close the device, i.e. the display connection */
-  static
-  void  done_device( void )
-  {
-    XCloseDisplay( display );
-  }
-
-
-
-  static
-  void add_pixel_mode( grPixelMode  pixel_mode,
-                       XDepth*      depth )
-  {
-    if ( num_pixel_modes >= MAX_PIXEL_MODES )
-      Panic( "X11.Too many pixel modes\n" );
-      
-    pixel_modes[ num_pixel_modes ] = pixel_mode;
-    pixel_depth[ num_pixel_modes ] = *depth;
-    
-    num_pixel_modes++;
-  }
-
-
-
-  static
-  int  init_device( void )
-  {
-    XDepth  dummy;
-  
-    XrmInitialize();
-    
-    display = XOpenDisplay( displayname );
-    if (!display)
-    {
-      return -1;
-     /* Panic( "Gr:error: cannot open X11 display\n" ); */
-    }
-      
-    idle = XCreateFontCursor( display, XC_left_ptr );
-    busy = XCreateFontCursor( display, XC_watch );
-    
-    num_pixel_modes = 0;
-    
-    /* always enable the 8-bit gray levels pixel mode                */
-    /* even if its display is emulated through a constrained palette */
-    /* or another color mode                                         */
-    dummy.depth          = 8;
-    dummy.bits_per_pixel = 8;
-    dummy.scanline_pad   = 8;
-    add_pixel_mode( gr_pixel_mode_gray, &dummy );
-
-    {
-      int          count;
-      XDepth*      format;
-      XDepth*      formats;
-      XVisualInfo  template;
-
-      formats = XListPixmapFormats( display, &count );
-      format  = formats;
-       
-#ifdef TEST
-      printf( "available pixmap formats\n" );
-      printf( "depth  pixbits  scanpad\n" );
-#endif
-       
-      while ( count-- > 0 )
-      {
-#ifdef TEST 
-        printf( " %3d     %3d      %3d\n",
-                format->depth,
-                format->bits_per_pixel,
-                format->scanline_pad );
-#endif
-      
-        if ( format->depth == 1 )
-          /* usually, this should be the first format */
-          add_pixel_mode( gr_pixel_mode_mono, format );
-          
-        else if ( format->depth == 8 )
-          add_pixel_mode( gr_pixel_mode_pal8, format );
-
-        /* note, the 32-bit modes return a depth of 24, and 32 bits per pixel */          
-        else if ( format->depth == 24 )
-        {
-          if ( format->bits_per_pixel == 24 )
-            add_pixel_mode( gr_pixel_mode_rgb24, format );
-            
-          else if ( format->bits_per_pixel == 32 )
-            add_pixel_mode( gr_pixel_mode_rgb32, format );
-        }
-          
-        else if ( format->depth == 16 )
-        {
-          int           count2;
-          XVisualInfo*  visuals;
-          XVisualInfo*  visual;
-
-          template.depth = format->depth;
-          visuals        = XGetVisualInfo( display,
-                                           VisualDepthMask,
-                                           &template,
-                                           &count2 );
-          visual = visuals;
-          
-          while ( count2-- > 0 )
-          {
-#ifdef TEST 
-            const char*  string = "unknown";
-            
-            switch (visual->class)
-            {
-              case TrueColor:   string = "TrueColor";    break;
-              case DirectColor: string = "DirectColor";  break;
-              case PseudoColor: string = "PseudoColor";  break;
-              case StaticGray : string = "StaticGray";   break;
-              case StaticColor: string = "StaticColor";  break;
-              case GrayScale:   string = "GrayScale";    break;
-            }
-
-            printf( ">   RGB %02x:%02x:%02x, colors %3d, bits %2d  %s\n",
-                    visual->red_mask,
-                    visual->green_mask,
-                    visual->blue_mask,
-                    visual->colormap_size,
-                    visual->bits_per_rgb,
-                    string );
-#endif
-            if ( visual->red_mask   == 0xf800 &&
-                 visual->green_mask == 0x07e0 &&
-                 visual->blue_mask  == 0x001f )
-              add_pixel_mode( gr_pixel_mode_rgb565, format );
-              
-            else if ( visual->red_mask   == 0x7c00 &&
-                      visual->green_mask == 0x03e0 &&
-                      visual->blue_mask  == 0x001f )
-              add_pixel_mode( gr_pixel_mode_rgb555, format );
-              
-            /* other 16-bit modes are ignored */  
-            visual++;
-          }
-          
-          XFree( visuals );
-        }
-        
-        format++;
-      }
-      
-      XFree( formats );
-    }
-    
-    gr_x11_device.num_pixel_modes = num_pixel_modes;
-    gr_x11_device.pixel_modes     = pixel_modes;
-    
-    return 0;
-  }
-
-
-
-
-
-
-
-
-
-
-
-
-  static
-  void  convert_gray_to_pal8( grXSurface*  surface,
-                              int          x,
-                              int          y,
-                              int          w,
-                              int          h )
-  {
-    grBitmap*  target  = &surface->image;
-    grBitmap*  source  = &surface->root.bitmap;
-    byte*      write   = (byte*)target->buffer + y*target->pitch + x;
-    byte*      read    = (byte*)source->buffer + y*source->pitch + x;
-    XColor*    palette = surface->color;
-    
-    while (h > 0)
-    {
-      byte*  _write = write;
-      byte*  _read  = read;
-      byte*  limit  = _write + w;
-      
-      for ( ; _write < limit; _write++, _read++ )
-        *_write = (byte) palette[ *_read ].pixel;
-
-      write += target->pitch;
-      read  += source->pitch;
-      h--;
-    }
-  }
-
-
-  static
-  void  convert_gray_to_16( grXSurface*  surface,
-                            int          x,
-                            int          y,
-                            int          w,
-                            int          h )
-  {
-    grBitmap*  target  = &surface->image;
-    grBitmap*  source  = &surface->root.bitmap;
-    byte*      write   = (byte*)target->buffer + y*target->pitch + 2*x;
-    byte*      read    = (byte*)source->buffer + y*source->pitch + x;
-    XColor*    palette = surface->color;
-    
-    while (h > 0)
-    {
-      byte*  _write = write;
-      byte*  _read  = read;
-      byte*  limit  = _write + 2*w;
-      
-      for ( ; _write < limit; _write += 2, _read++ )
-        *(short*)_write = (short)palette[ *_read ].pixel;
-
-      write += target->pitch;
-      read  += source->pitch;
-      h--;
-    }
-  }
-
-
-  static
-  void  convert_gray_to_24( grXSurface*  surface,
-                            int          x,
-                            int          y,
-                            int          w,
-                            int          h )
-  {
-    grBitmap*  target  = &surface->image;
-    grBitmap*  source  = &surface->root.bitmap;
-    byte*      write   = (byte*)target->buffer + y*target->pitch + 3*x;
-    byte*      read    = (byte*)source->buffer + y*source->pitch + x;
-    
-    while (h > 0)
-    {
-      byte*  _write = write;
-      byte*  _read  = read;
-      byte*  limit  = _write + 3*w;
-      
-      for ( ; _write < limit; _write += 3, _read++ )
-      {
-        byte  color = *_read;
-        
-        _write[0] =
-        _write[1] =
-        _write[2] = color;
-      }
-
-      write += target->pitch;
-      read  += source->pitch;
-      h--;
-    }
-  }
-
-
-  static
-  void  convert_gray_to_32( grXSurface*  surface,
-                            int          x,
-                            int          y,
-                            int          w,
-                            int          h )
-  {
-    grBitmap*  target  = &surface->image;
-    grBitmap*  source  = &surface->root.bitmap;
-    byte*      write   = (byte*)target->buffer + y*target->pitch + 4*x;
-    byte*      read    = (byte*)source->buffer + y*source->pitch + x;
-    
-    while (h > 0)
-    {
-      byte*  _write = write;
-      byte*  _read  = read;
-      byte*  limit  = _write + 4*w;
-      
-      for ( ; _write < limit; _write += 4, _read++ )
-      {
-        byte  color = *_read;
-        
-        _write[0] =
-        _write[1] =
-        _write[2] =
-        _write[3] = color;
-      }
-
-      write += target->pitch;
-      read  += source->pitch;
-      h--;
-    }
-  }
-
-
-  static
-  void  convert_rectangle( grXSurface*  surface,
-                           int          x,
-                           int          y,
-                           int          w,
-                           int          h )
-  {
-    int  z;
-    
-    /* first of all, clip to the surface's area */
-    if ( x   >= surface->image.width ||
-         x+w <= 0                    ||
-         y   >= surface->image.rows  ||
-         y+h <= 0 )
-      return;
- 
-    if ( x < 0 )
-    {
-      w += x;
-      x  = 0;
-    }
- 
-    z = (x + w) - surface->image.width;
-    if (z > 0)
-      w -= z;
-      
-    z = (y + h) - surface->image.rows;
-    if (z > 0)
-      h -= z;
-      
-    /* convert the rectangle to the target depth for gray surfaces */
-    if (surface->gray)
-    {
-      switch (surface->depth)
-      {
-        case 8 : convert_gray_to_pal8( surface, x, y, w, h ); break;
-        case 16: convert_gray_to_16  ( surface, x, y, w, h ); break;
-        case 24: convert_gray_to_24  ( surface, x, y, w, h ); break;
-        case 32: convert_gray_to_32  ( surface, x, y, w, h ); break;
-      }
-    }
-  } 
-
-
-  static
-  void  refresh_rectangle( grXSurface*  surface,
-                           int          x,
-                           int          y,
-                           int          w,
-                           int          h )
-  {
-    if (surface->gray)
-      convert_rectangle( surface, x, y, w, h );
-    
-    XPutImage( display,
-               surface->win,
-               surface->gc,
-               surface->ximage,
-               x, y, x, y, w, h );
-  }
-
-  
-  static
-  void  set_title( grXSurface*  surface,
-                   const char*  title )
-  {
-    XStoreName( display, surface->win, title );
-  }
-
-
-
-  static
-  grKey  KeySymTogrKey( KeySym  key )
-  {
-    grKey        k;
-    int          count = sizeof(key_translators)/sizeof(key_translators[0]);
-    Translator*  trans = key_translators;
-    Translator*  limit = trans + count;
-
-    k = grKeyNone;
-
-    while ( trans < limit )
-    {
-      if ( trans->xkey == key )
-      {
-        k = trans->grkey;
-        break;
-      }
-      trans++;
-    }
-
-    return k;
-  }
-
-
-
-  static  
-  void  listen_event( grXSurface*  surface,
-                      int          event_mask,
-                      grEvent*     grevent )
-  {
-    static char     key_buffer[10];
-    static int      key_cursor = 0;
-    static int      key_number = 0;
-    static XEvent   x_event;
-           KeySym   key;
-
-    int             bool_exit;
-    grKey           grkey;
-
-    XComposeStatus  compose;
-
-    /* XXXX : For now, ignore the event mask, and only exit when */
-    /*        a key is pressed..                                 */
-    (void)event_mask;
-
-    bool_exit = key_cursor < key_number;
-
-    XDefineCursor( display, surface->win, idle );
-
-    while ( !bool_exit )
-    {
-      XNextEvent( display, &x_event );
-
-      switch ( x_event.type )
-      {
-      case KeyPress: 
-        key_number = XLookupString( &x_event.xkey,
-                                    key_buffer,
-                                    sizeof ( key_buffer ),
-                                    &key,
-                                    &compose );
-        key_cursor = 0;
-
-        if ( key_number == 0 ||
-             key > 512       )
-        {
-          /* this may be a special key like F1, F2, etc.. */
-          grkey = KeySymTogrKey(key);
-          if (grkey != grKeyNone)
-            goto Set_Key;  
-        }
-        else
-          bool_exit = 1;
-        break;
-
-      case MappingNotify:
-        XRefreshKeyboardMapping( &x_event.xmapping );
-        break;
-      
-      case Expose:
-        refresh_rectangle( surface,
-                           x_event.xexpose.x,
-                           x_event.xexpose.y,
-                           x_event.xexpose.width,
-                           x_event.xexpose.height );
-        break;
-
-      /* You should add more cases to handle mouse events, etc. */
-      }
-    }
-
-    XDefineCursor( display, surface->win, busy );
-    XFlush       ( display );
-
-    /* Now, translate the keypress to a grKey */
-    /* If this wasn't part of the simple translated keys, simply get the charcode */
-    /* from the character buffer                                                  */
-    grkey = grKEY(key_buffer[key_cursor++]);
-      
-  Set_Key:
-    grevent->type = gr_key_down;
-    grevent->key  = grkey;
-  }
-
-
-
-
-  grXSurface*  init_surface( grXSurface*  surface,
-                             grBitmap*    bitmap )
-  {
-    int        screen;
-    grBitmap*  image;
-    char       grays;
-    XDepth*    format;
-    int        image_depth;
-    
-    screen = DefaultScreen( display );
-    
-    surface->colormap = DefaultColormap( display, screen );
-    surface->depth    = DefaultDepth( display, screen );
-    surface->visual   = DefaultVisual( display, screen ); 
-
-    image  = &surface->image;
-
-    /* force the surface image depth to 1 if necessary */
-    /* as this should be supported by all windows      */
-    image_depth = surface->depth;
-    if (bitmap->mode == gr_pixel_mode_mono)
-      image_depth = 1;
-
-    grays = ( bitmap->mode == gr_pixel_mode_gray &&
-              bitmap->grays >= 2 );
-
-    surface->gray = grays;
- 
-    /* copy dimensions */
-    image->width  = bitmap->width;
-    image->rows   = bitmap->rows;
-    image->mode   = bitmap->mode;
-    image->pitch  = 0;
-    image->grays  = 0;
-    image->buffer = 0;
-
-    /* find the supported format corresponding to the request */
-    format = 0;
-
-    if (grays)    
-    {
-      /* choose the default depth in case of grays rendering */
-      int  i;
-      for ( i = 0; i < num_pixel_modes; i++ )
-        if ( image_depth == pixel_depth[i].depth )
-        {
-          format = pixel_depth + i;
-          break;
-        }
-    }
-    else
-    {
-      /* otherwise, select the format depending on the pixel mode */
-      int  i;
-      
-      format = 0;
-      for ( i = 0; i < num_pixel_modes; i++ )
-        if ( pixel_modes[i] == bitmap->mode )
-        {
-          format = pixel_depth + i;
-          break;
-        }
-    }
-    
-    if (!format)
-    {
-      grError = gr_err_bad_argument;
-      return 0;
-    }
-
-
-    /* correct surface.depth. This is required because in the case    */
-    /* of 32-bits pixels, the value of "format.depth" is 24 under X11 */
-    if ( format->depth          == 24 &&
-         format->bits_per_pixel == 32 )
-      image_depth = 32;
-     
-    /* allocate surface image */
-    {
-      int  bits, over;
-
-      bits = image->width * format->bits_per_pixel;
-      over = bits % format->scanline_pad;
-          
-      if (over)
-        bits += format->scanline_pad - over;
-      
-      if (!grays)
-      {
-        image->width  = bits;
-        bitmap->width = bits;
-      }
-      image->pitch  = bits >> 3;
-    }
-
-    image->buffer = grAlloc( image->pitch * image->rows );
-    if (!image->buffer) return 0;
-
-    /* now, allocate a gray pal8 pixmap, only when we asked */
-    /* for an 8-bit pixmap                                  */
-    if ( grays )
-    {
-      /* pad pitch to 32 bits */
-      bitmap->pitch  = (bitmap->width + 3) & -4;
-      bitmap->buffer = grAlloc( bitmap->pitch * bitmap->rows );
-      if (!bitmap->buffer)
-        Panic( "grX11: could not allocate surface bitmap!\n" );
-    }
-    else  /* otherwise */
-    {
-      *bitmap = *image;
-    }
-
-    surface->root.bitmap = *bitmap;
- 
-    /* Now create the surface X11 image */
-    surface->ximage = XCreateImage( display, 
-                                    surface->visual,
-                                    format->depth,
-                                    format->depth == 1 ? XYBitmap : ZPixmap,
-                                    0,
-                                    (char*)image->buffer,
-                                    image->width,
-                                    image->rows,
-                                    8,
-                                    0 );
-    if ( !surface->ximage )
-      Panic( "grX11: cannot create surface X11 image\n" );
- 
-
-    /* allocate gray levels in the case of gray surface */
-    if ( grays )
-    {
-      XColor*  color = surface->color;
-      int      i;
-      
-      for ( i = 0; i < bitmap->grays; i++, color++ )
-      {
-        color->red   =
-        color->green =
-        color->blue  = 65535 - ( i * 65535 ) / bitmap->grays;
-  
-        if ( !XAllocColor( display, surface->colormap, color ) )
-          Panic( "ERROR: cannot allocate Color\n" );
-      }
-    }
-    else if ( image_depth == 1 )
-    {
-      surface->ximage->byte_order       = MSBFirst;
-      surface->ximage->bitmap_bit_order = MSBFirst;
-    }
-
-    {
-        XTextProperty         xtp;
-        XSizeHints            xsh;
-        XSetWindowAttributes  xswa;
-    
-        xswa.border_pixel     = BlackPixel( display, screen );
-        xswa.background_pixel = WhitePixel( display, screen );
-        xswa.cursor           = busy;
-    
-        xswa.event_mask = KeyPressMask | ExposureMask;
-    
-        surface->win = XCreateWindow( display,
-                                      RootWindow( display, screen ),
-                                      0,
-                                      0,
-                                      image->width,
-                                      image->rows,
-                                      10,
-                                      surface->depth,
-                                      InputOutput, 
-                                      surface->visual,
-                                      CWBackPixel | CWBorderPixel |
-                                        CWEventMask | CWCursor,
-                                      &xswa );
-    
-        XMapWindow( display, surface->win );
- 
-        surface->gc = XCreateGC( display, RootWindow( display, screen ), 0L, NULL );
-        XSetForeground( display, surface->gc, xswa.border_pixel     );
-        XSetBackground( display, surface->gc, xswa.background_pixel );
-    
-    
-        /* make window manager happy :-) */
-        xtp.value    = (unsigned char*)"FreeType";
-        xtp.encoding = 31;
-        xtp.format   = 8;
-        xtp.nitems   = strlen( (char*)xtp.value );
-    
-        xsh.x = 0;
-        xsh.y = 0;
-    
-        xsh.width  = image->width;
-        xsh.height = image->rows;
-        xsh.flags  = (PPosition | PSize);
-        xsh.flags  = 0;
-    
-        XSetWMProperties( display, surface->win, &xtp, &xtp, NULL, 0, &xsh, NULL, NULL );
-    }
-    
-    surface->root.done         = (grDoneSurfaceFunc) done_surface;
-    surface->root.refresh_rect = (grRefreshRectFunc) refresh_rectangle;
-    surface->root.set_title    = (grSetTitleFunc)    set_title;
-    surface->root.listen_event = (grListenEventFunc) listen_event;
-    
-    convert_rectangle( surface, 0, 0, bitmap->width, bitmap->rows );
-    return surface;
-  }
-  
-
-
-
-  grDevice  gr_x11_device =
-  {
-    sizeof( grXSurface ),
-    "x11",
-    
-    init_device,
-    done_device,
-    
-    (grDeviceInitSurfaceFunc) init_surface,
-    
-    0,
-    0
-    
-  };
-
-#ifdef TEST
-
-typedef struct grKeyName
-{
-  grKey       key;
-  const char* name;
-
-} grKeyName;
-
-
-static
-const grKeyName  key_names[] =
-{
-  { grKeyF1,   "F1"  },
-  { grKeyF2,   "F2"  },
-  { grKeyF3,   "F3"  },
-  { grKeyF4,   "F4"  },
-  { grKeyF5,   "F5"  },
-  { grKeyF6,   "F6"  },
-  { grKeyF7,   "F7"  },
-  { grKeyF8,   "F8"  },
-  { grKeyF9,   "F9"  },
-  { grKeyF10,  "F10" },
-  { grKeyF11,  "F11" },
-  { grKeyF12,  "F12" },
-  { grKeyEsc,  "Esc" },
-  { grKeyHome, "Home" },
-  { grKeyEnd,  "End"  },
-    
-  { grKeyPageUp,   "Page_Up" },
-  { grKeyPageDown, "Page_Down" },
-  { grKeyLeft,     "Left" },
-  { grKeyRight,    "Right" },
-  { grKeyUp,       "Up" },
-  { grKeyDown,     "Down" },
-  { grKeyBackSpace, "BackSpace" },
-  { grKeyReturn,   "Return" }
-};
-
-int  main( void )
-{
-  grSurface*  surface;
-  int         n;
-  
-  grInit();
-  surface = grNewScreenSurface( 0, gr_pixel_mode_gray, 320, 400, 128 );
-  if (!surface)
-    Panic("Could not create window\n" );
-  else
-  {
-    grColor      color;
-    grEvent      event;
-    const char*  string;
-    int          x;
-    
-    grSetSurfaceRefresh( surface, 1 );
-    grSetTitle(surface,"X11 driver demonstration" );
-    
-    for ( x = -10; x < 10; x++ )
-    {
-      for ( n = 0; n < 128; n++ )
-      {
-        color.value = (n*3) & 127;
-        grWriteCellChar( surface,
-                         x + ((n % 60) << 3),
-                         80 + (x+10)*8*3 + ((n/60) << 3), n, color );
-      }
-
-    }
-    color.value = 64;
-    grWriteCellString( surface, 0, 0, "just an example", color );
-    
-    do
-    {
-      listen_event((grXSurface*)surface, 0, &event);
-    
-      /* return if ESC was pressed */
-      if ( event.key == grKeyEsc )
-        return 0;
-      
-      /* otherwise, display key string */
-      color.value = (color.value + 8) & 127;
-      {
-        int         count = sizeof(key_names)/sizeof(key_names[0]);
-        grKeyName*  name  = key_names;
-        grKeyName*  limit = name + count;
-        const char* kname  = 0;
-        char        kname_temp[16];
-      
-        while (name < limit)
-        {
-          if ( name->key == event.key )
-          {
-            kname = name->name;
-            break;
-          }
-          name++;
-        }
-      
-        if (!kname)
-        {
-          sprintf( kname_temp, "char '%c'", (char)event.key );
-          kname = kname_temp;
-        }
-        
-        grWriteCellString( surface, 30, 30, kname, color );
-        grRefreshSurface(surface);
-        paint_rectangle( surface, 0, 0, surface->bitmap.width, surface->bitmap.rows );
-      }
-    } while (1);
-  }
-    
-  return 0;
-  
-  
-}
-#endif /* TEST */
-
--- a/demos/graph/grx11.h
+++ /dev/null
@@ -1,24 +1,0 @@
-#ifndef GRX11_H
-#define GRX11_H
-
-#include "grobjs.h"
-#include "grdevice.h"
-
-  extern
-  grDevice  gr_x11_device;
-
-#ifdef GR_INIT_BUILD
-  static
-  grDeviceChain  gr_x11_device_chain =
-  {
-    "x11",
-    &gr_x11_device,
-    GR_INIT_DEVICE_CHAIN
-  };
-
-#undef GR_INIT_DEVICE_CHAIN
-#define GR_INIT_DEVICE_CHAIN  &gr_x11_device_chain
-
-#endif  /* GR_INIT_BUILD */
-
-#endif /* GRX11_H */
--- /dev/null
+++ b/demos/graph/os2/gros2pm.c
@@ -1,0 +1,754 @@
+#include "gros2pm.h"
+#include "grdevice.h"
+
+#define INCL_DOS
+#define INCL_WIN
+#define INCL_GPI
+#define INCL_SUB
+
+#include <os2.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#define  DEBUGxxx
+
+#ifdef DEBUG
+#define LOG(x)  LogMessage##x
+#else
+#define LOG(x)  /* rien */
+#endif
+
+#ifdef DEBUG
+  static void  LogMessage( const char*  fmt, ... )
+  {
+    va_list  ap;
+
+    va_start( ap, fmt );
+    vfprintf( stderr, fmt, ap );
+    va_end( ap );
+  }
+#endif
+
+  typedef struct Translator
+  {
+    ULONG   os2key;
+    grKey   grkey;
+    
+  } Translator;
+  
+
+  static
+  Translator  key_translators[] =
+  {
+    { VK_BACKSPACE, grKeyBackSpace },
+    { VK_TAB,       grKeyTab       },
+    { VK_ENTER,     grKeyReturn    },
+    { VK_ESC,       grKeyEsc       },
+    { VK_HOME,      grKeyHome      },
+    { VK_LEFT,      grKeyLeft      },
+    { VK_UP,        grKeyUp        },
+    { VK_RIGHT,     grKeyRight     },
+    { VK_DOWN,      grKeyDown      },
+    { VK_PAGEUP,    grKeyPageUp    },
+    { VK_PAGEDOWN,  grKeyPageDown  },
+    { VK_END,       grKeyEnd       },
+    { VK_F1,        grKeyF1        },
+    { VK_F2,        grKeyF2        },
+    { VK_F3,        grKeyF3        },
+    { VK_F4,        grKeyF4        },
+    { VK_F5,        grKeyF5        },
+    { VK_F6,        grKeyF6        },
+    { VK_F7,        grKeyF7        },
+    { VK_F8,        grKeyF8        },
+    { VK_F9,        grKeyF9        },
+    { VK_F10,       grKeyF10       },
+    { VK_F11,       grKeyF11       },
+    { VK_F12,       grKeyF12       }
+  };
+
+
+#define MAX_PIXEL_MODES  32
+
+  static  HAB   gr_anchor;   /* device anchor block */
+
+  typedef POINTL  PMBlitPoints[4];
+
+  typedef struct grPMSurface_
+  {
+    grSurface  root;
+    grBitmap   image;
+
+    HAB        anchor;         /* handle to anchor block for surface's window */
+    HWND       frame_window;   /* handle to window's frame                    */
+    HWND       client_window;  /* handle to window's client                   */
+    HWND       title_window;   /* handle to window's title bar                */
+
+    HPS        image_ps;       /* memory presentation space used to hold */
+                               /* the surface's content under PM         */
+    HDC        image_dc;       /* memory device context for the image    */
+
+    HEV        event_lock;     /* semaphore used in listen_surface   */
+    HMTX       image_lock;     /* a mutex used to synchronise access */
+                               /* to the memory presentation space   */
+                               /* used to hold the surface           */
+
+    TID        message_thread; /* thread used to process this surface's */
+                               /* messages..                            */
+
+    PBITMAPINFO2 bitmap_header;/* os/2 bitmap descriptor                   */
+    HBITMAP      os2_bitmap;   /* Handle to OS/2 bitmap contained in image */
+    BOOL         ready;        /* ??? */
+
+    long         shades[256];  /* indices of gray levels in pixel_mode_gray */
+
+    POINTL       surface_blit[4];  /* surface blitting table   */
+    POINTL       magnify_blit[4];  /* magnifier blitting table */
+    int          magnification;    /* level of magnification   */
+    POINTL       magnify_center;
+    SIZEL        magnify_size;
+
+    grEvent      event;
+
+    PMBlitPoints blit_points;
+
+  } grPMSurface;
+
+  /* we use a static variable to pass a pointer to the PM Surface  */
+  /* to the client window. This is a bit ugly, but it makes things */
+  /* a lot more simple..                                           */
+  static  grPMSurface*  the_surface;
+
+  static  int window_created = 0;
+
+
+  static
+  void  enable_os2_iostreams( void )
+  {
+    PTIB  thread_block;
+    PPIB  process_block;
+
+    /* XXX : This is a very nasty hack, it fools OS/2 and let the program */
+    /*       call PM functions, even though stdin/stdout/stderr are still */
+    /*       directed to the standard i/o streams..                       */
+    /*       The program must be compiled with WINDOWCOMPAT               */
+    /*                                                                    */
+    /*   Credits go to Michal for finding this !!                         */
+    /*                                                                    */
+    DosGetInfoBlocks( &thread_block, &process_block );
+    process_block->pib_ultype = 3;
+  }
+
+
+
+  static
+  int  init_device( void )
+  {
+    enable_os2_iostreams();
+
+    /* create an anchor block. This will allow this thread (i.e. the */
+    /* main one) to call Gpi functions..                             */
+    gr_anchor = WinInitialize(0);
+    if (!gr_anchor)
+    {
+      /* could not initialise Presentation Manager */
+      return -1;
+    }
+
+    return 0;
+  }
+
+
+
+  static
+  void  done_device( void )
+  {
+    /* Indicates that we do not use the Presentation Manager, this */
+    /* will also release all associated resources..                */
+    WinTerminate( gr_anchor );
+  }
+
+
+
+  /* close a given window */
+  static
+  void  done_surface( grPMSurface*  surface )
+  {
+    LOG(( "Os2PM: done_surface(%08lx)\n", (long)surface ));
+
+    if ( surface->frame_window )
+      WinDestroyWindow( surface->frame_window );
+
+    WinReleasePS( surface->image_ps );
+
+    grDoneBitmap( &surface->image );
+    grDoneBitmap( &surface->root.bitmap );
+  }
+
+
+
+
+
+#define LOCK(x)    DosRequestMutexSem( x, SEM_INDEFINITE_WAIT );
+#define UNLOCK(x)  DosReleaseMutexSem( x )
+
+
+  static
+  const int  pixel_mode_bit_count[] =
+  {
+    0,
+    1,   /* mono  */
+    4,   /* pal4  */
+    8,   /* pal8  */
+	8,   /* grays */
+    15,  /* rgb15 */
+    16,  /* rgb16 */
+    24,  /* rgb24 */
+    32   /* rgb32 */
+  };
+
+
+ /************************************************************************
+  *
+  * Technical note : how the OS/2 Presntation Manager driver works
+  *
+  * PM is, in my opinion, a bloated and over-engineered graphics
+  * sub-system, even though it has lots of nice features. Here are
+  * a few tidbits about it :
+  *
+  *
+  * - under PM, a "bitmap" is a device-specific object whose bits are
+  *   not directly accessible to the client application. This means
+  *   that we must use a scheme like the following to display our
+  *   surfaces :
+  *
+  *     - hold, for each surface, its own bitmap buffer where the
+  *       rest of the graph library writes directly.
+  *
+  *     - create a PM bitmap object with the same dimensions (and
+  *       possibly format).
+  *
+  *     - copy the content of each updated rectangle into the
+  *       PM bitmap with the function 'GpiSetBitmapBits'.
+  *
+  *     - finally, "blit" the PM bitmap to the screen calling
+  *       'GpiBlitBlt'
+  *
+  * - but there is more : you cannot directly blit a PM bitmap to the
+  *   screen with PM. The 'GpiBlitBlt' only works with presentation
+  *   spaces. This means that we also need to create, for each surface :
+  *
+  *     - a memory presentation space, used to hold the PM bitmap
+  *     - a "memory device context" for the presentation space
+  *
+  *   The blit is then performed from the memory presentation space
+  *   to the screen's presentation space..
+  *
+  *
+  * - because each surface creates its own event-handling thread,
+  *   we must protect the surface's presentation space from concurrent
+  *   accesses (i.e. calls to 'GpiSetBitmapBits' when drawing to the
+  *   surface, and calls to 'GpiBlitBlt' when drawing it on the screen
+  *   are performed in two different threads).
+  *
+  *   we use a simple mutex to do this.
+  *
+  *
+  * - we also use a semaphore to perform a rendez-vous between the
+  *   main and event-handling threads (needed in "listen_event").
+  *
+  ************************************************************************/
+
+  static
+  void  RunPMWindow( grPMSurface*  surface );
+
+
+
+
+  static
+  void  refresh_rectangle( grPMSurface* surface,
+                           int          x,
+                           int          y,
+                           int          w,
+                           int          h )
+  {
+    LOG(( "Os2PM: refresh_rectangle( %08lx, %d, %d, %d, %d )\n",
+          (long)surface, x, y, w, h ));
+
+    (void)x;
+    (void)y;
+    (void)w;
+    (void)h;
+
+    /*
+    convert_rectangle( surface, x, y, w, h );
+    */
+    DosRequestMutexSem( surface->image_lock, SEM_INDEFINITE_WAIT );
+    GpiSetBitmapBits( surface->image_ps,
+                      0,
+                      surface->root.bitmap.rows,
+                      surface->root.bitmap.buffer,
+                      surface->bitmap_header );
+    DosReleaseMutexSem( surface->image_lock );
+
+    WinInvalidateRect( surface->client_window, NULL, FALSE );
+    WinUpdateWindow( surface->frame_window );
+  }
+
+  
+  static
+  void  set_title( grPMSurface* surface,
+                   const char*  title )
+  {
+    ULONG  rc;
+
+#if 1
+    LOG(( "Os2PM: set_title( %08lx == %08lx, %s )\n",
+             (long)surface, surface->client_window, title ));
+#endif
+    LOG(( "      -- frame         = %08lx\n",
+          (long)surface->frame_window ));
+
+    LOG(( "      -- client parent = %08lx\n",
+          (long)WinQueryWindow( surface->client_window, QW_PARENT ) ));
+
+    rc = WinSetWindowText( surface->client_window, (PSZ)title );
+    LOG(( "      -- returned rc = %ld\n",rc ));
+  }
+
+
+
+  static  
+  void  listen_event( grPMSurface* surface,
+                      int          event_mask,
+                      grEvent*     grevent )
+  {
+    ULONG  ulRequestCount;
+
+    (void) event_mask;   /* ignored for now */
+
+    /* the listen_event function blocks until there is an event to process */
+    DosWaitEventSem( surface->event_lock, SEM_INDEFINITE_WAIT );
+    DosQueryEventSem( surface->event_lock, &ulRequestCount );
+    *grevent = surface->event;
+    DosResetEventSem( surface->event_lock, &ulRequestCount );
+
+    return;
+  }
+
+
+  static
+  grPMSurface*  init_surface( grPMSurface*  surface,
+                              grBitmap*     bitmap )
+  {
+    PBITMAPINFO2  bit;
+    SIZEL         sizl = { 0, 0 };
+    LONG          palette[256];
+
+    LOG(( "Os2PM: init_surface( %08lx, %08lx )\n",
+          (long)surface, (long)bitmap ));
+
+    LOG(( "       -- input bitmap =\n" ));
+    LOG(( "       --   mode   = %d\n", bitmap->mode ));
+    LOG(( "       --   grays  = %d\n", bitmap->grays ));
+    LOG(( "       --   width  = %d\n", bitmap->width ));
+    LOG(( "       --   height = %d\n", bitmap->rows ));
+
+    /* create the bitmap - under OS/2, we support all modes as PM */
+    /* handles all conversions automatically..                    */
+    if ( grNewBitmap( bitmap->mode,
+                      bitmap->grays,
+					  bitmap->width,
+					  bitmap->rows,
+                      bitmap ) )
+      return 0;
+
+    LOG(( "       -- output bitmap =\n" ));
+    LOG(( "       --   mode   = %d\n", bitmap->mode ));
+    LOG(( "       --   grays  = %d\n", bitmap->grays ));
+    LOG(( "       --   width  = %d\n", bitmap->width ));
+    LOG(( "       --   height = %d\n", bitmap->rows ));
+
+    bitmap->pitch = -bitmap->pitch;
+    surface->root.bitmap = *bitmap;
+
+    /* create the image and event lock */
+    DosCreateEventSem( NULL, &surface->event_lock, 0, TRUE  );
+    DosCreateMutexSem( NULL, &surface->image_lock, 0, FALSE );
+
+    /* create the image's presentation space */
+    surface->image_dc = DevOpenDC( gr_anchor,
+                                   OD_MEMORY, (PSZ)"*", 0L, 0L, 0L );
+
+    surface->image_ps = GpiCreatePS( gr_anchor,
+                                     surface->image_dc,
+                                     &sizl,
+                                     PU_PELS    | GPIT_MICRO |
+                                     GPIA_ASSOC | GPIF_DEFAULT );
+
+    GpiSetBackMix( surface->image_ps, BM_OVERPAINT );
+
+    /* create the image's PM bitmap */
+    bit = (PBITMAPINFO2)grAlloc( sizeof(BITMAPINFO2) + 256*sizeof(RGB2) );
+    surface->bitmap_header = bit;
+
+    bit->cbFix   = sizeof( BITMAPINFOHEADER2 );
+    bit->cx      = surface->root.bitmap.width;
+    bit->cy      = surface->root.bitmap.rows;
+    bit->cPlanes = 1;
+
+    bit->argbColor[0].bBlue  = 255;
+    bit->argbColor[0].bGreen = 0;
+    bit->argbColor[0].bRed   = 0;
+
+    bit->argbColor[1].bBlue  = 0;
+    bit->argbColor[1].bGreen = 255;
+    bit->argbColor[1].bRed   = 0;
+
+    bit->cBitCount = (bitmap->mode == gr_pixel_mode_gray ? 8 : 1 );
+
+    if (bitmap->mode == gr_pixel_mode_gray)
+    {
+      RGB2*  color = bit->argbColor;
+      int    x, count;
+
+      count = bitmap->grays;
+      for ( x = 0; x < count; x++, color++ )
+      {
+        color->bBlue  =
+        color->bGreen =
+        color->bRed   = (((count-x)*255)/count);
+      }
+    }
+    else
+    {
+      RGB2*  color = bit->argbColor;
+
+      color[0].bBlue  =
+      color[0].bGreen =
+      color[0].bRed   = 0;
+
+      color[1].bBlue  =
+      color[1].bGreen =
+      color[1].bRed   = 255;
+    }
+
+    surface->os2_bitmap = GpiCreateBitmap( surface->image_ps,
+                                           (PBITMAPINFOHEADER2)bit,
+                                           0L, NULL, NULL );
+
+    GpiSetBitmap( surface->image_ps, surface->os2_bitmap );
+
+    bit->cbFix = sizeof( BITMAPINFOHEADER2 );
+    GpiQueryBitmapInfoHeader( surface->os2_bitmap,
+                              (PBITMAPINFOHEADER2)bit );
+    surface->bitmap_header = bit;
+
+    /* for gr_pixel_mode_gray, create a gray-levels logical palette */
+    if ( bitmap->mode == gr_pixel_mode_gray )
+    {
+      int     x, count;
+
+      count = bitmap->grays;
+      for ( x = 0; x < count; x++ )
+        palette[x] = (((count-x)*255)/count) * 0x010101;
+
+      /* create logical color table */
+      GpiCreateLogColorTable( surface->image_ps,
+                              (ULONG) LCOL_PURECOLOR,
+                              (LONG)  LCOLF_CONSECRGB,
+                              (LONG)  0L,
+                              (LONG)  count,
+                              (PLONG) palette );
+
+      /* now, copy the color indexes to surface->shades */
+      for ( x = 0; x < count; x++ )
+        surface->shades[x] = GpiQueryColorIndex( surface->image_ps,
+                                                 0, palette[x] );
+    }
+
+    /* set up the blit points array */
+    surface->blit_points[1].x = surface->root.bitmap.width;
+    surface->blit_points[1].y = surface->root.bitmap.rows;
+    surface->blit_points[3]   = surface->blit_points[1];
+
+    window_created = 0;
+
+    /* Finally, create the event handling thread for the surface's window */
+    DosCreateThread( &surface->message_thread,
+                     (PFNTHREAD) RunPMWindow,
+                     (ULONG)     surface,
+                     0UL,
+                     32920 );
+
+    /* wait for the window creation */
+    for ( ; window_created == 0; )
+
+    surface->root.done         = (grDoneSurfaceFunc) done_surface;
+    surface->root.refresh_rect = (grRefreshRectFunc) refresh_rectangle;
+    surface->root.set_title    = (grSetTitleFunc)    set_title;
+    surface->root.listen_event = (grListenEventFunc) listen_event;
+
+    /* convert_rectangle( surface, 0, 0, bitmap->width, bitmap->rows ); */
+    return surface;
+  }
+
+
+
+  MRESULT EXPENTRY  Message_Process( HWND    handle,
+                                     ULONG   mess,
+                                     MPARAM  parm1,
+                                     MPARAM  parm2 );
+
+
+  static
+  void  RunPMWindow( grPMSurface*  surface )
+  {
+    unsigned char   class_name[] = "DisplayClass";
+             ULONG  class_flags;
+
+    static   HMQ    queue;
+             QMSG   message;
+
+    /* store the current surface pointer in "the_surface". It is a static */
+    /* variable that is only used to retrieve the pointer in the client   */
+    /* window procedure the first time is is called..                     */
+    the_surface = surface;
+
+    LOG(( "Os2PM: RunPMWindow( %08lx )\n", (long)surface ));
+     
+    /* create an anchor to allow this thread to use PM */
+    surface->anchor = WinInitialize(0);
+    if (!surface->anchor)
+    {
+      printf( "Error doing WinInitialize()\n" );
+      return;
+    }
+
+    /* create a message queue */
+    queue = WinCreateMsgQueue( surface->anchor, 0 );
+    if (!queue)
+    {
+      printf( "Error doing >inCreateMsgQueue()\n" );
+      return;
+    }
+
+    /* register the window class */
+    if ( !WinRegisterClass( surface->anchor,
+                            (PSZ)   class_name,
+                            (PFNWP) Message_Process,
+                            CS_SIZEREDRAW,
+                            0 ) )
+    {
+      printf( "Error doing WinRegisterClass()\n" );
+      return;
+    }
+
+    /* create the PM window */
+    class_flags = FCF_TITLEBAR | FCF_MINBUTTON | FCF_DLGBORDER | 
+                  FCF_TASKLIST | FCF_SYSMENU; 
+
+    LOG(( "Os2PM: RunPMWindow: Creating window\n" ));
+    surface->frame_window = WinCreateStdWindow(
+                                HWND_DESKTOP,
+                                WS_VISIBLE,
+                                &class_flags,
+                                (PSZ) class_name,
+                                (PSZ) "FreeType Viewer - press F1 for help",
+                                WS_VISIBLE,
+                                0, 0,
+                                &surface->client_window );
+    if (!surface->frame_window)
+    {
+      printf( "Error doing WinCreateStdWindow()\n" );
+      return;
+    }
+
+    /* find the title window handle */
+    surface->title_window = WinWindowFromID( surface->frame_window,
+                                             FID_TITLEBAR );
+    LOG (( "Os2PM: RunPMWIndow: Creation succeeded\n" ));
+    LOG (( "    -- frame  = %08lx\n", surface->frame_window ));
+    LOG (( "    -- client = %08lx\n", surface->client_window ));
+
+    /* set Window size and position */
+    WinSetWindowPos( surface->frame_window,
+                     0L,
+                     (SHORT) 60,
+
+                     (SHORT) WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN ) -
+                             (surface->root.bitmap.rows + 100),
+
+                     (SHORT) WinQuerySysValue( HWND_DESKTOP, SV_CYDLGFRAME )*2 +
+                             surface->root.bitmap.width,
+
+                     (SHORT) WinQuerySysValue( HWND_DESKTOP, SV_CYTITLEBAR ) +
+                             WinQuerySysValue( HWND_DESKTOP, SV_CYDLGFRAME )*2 +
+                             surface->root.bitmap.rows,
+
+                     SWP_SIZE | SWP_MOVE );
+
+#if 0
+    /* save the handle to the current surface within the window words */
+    WinSetWindowPtr( surface->client_window,QWL_USER, surface );
+#endif
+
+    window_created = 1;
+
+    /* run the message queue till the end */
+    while ( WinGetMsg( surface->anchor, &message, (HWND)NULL, 0, 0 ) )
+    {
+      WinDispatchMsg( surface->anchor, &message );
+    }
+
+    /* clean-up */
+    WinDestroyWindow( surface->frame_window );
+    surface->frame_window = 0;
+
+    WinDestroyMsgQueue( queue );
+    WinTerminate( surface->anchor );
+
+    /* await death... */
+    while ( 1 )
+      DosSleep( 100 );
+  }
+
+
+
+
+  /* Message processing for our PM Window class */
+  MRESULT EXPENTRY  Message_Process( HWND    handle,
+                                     ULONG   mess,
+                                     MPARAM  parm1,
+                                     MPARAM  parm2 )
+  {
+     static HDC     screen_dc;
+     static HPS     screen_ps;
+     static BOOL    minimized;
+
+     SIZEL   sizl;
+     SWP     swp;
+
+     grPMSurface*  surface;
+
+    /* get the handle to the window's surface -- note that this */
+    /* value will be null when the window is created            */
+    surface = (grPMSurface*)WinQueryWindowPtr( handle, QWL_USER );
+    if (!surface)
+    {
+      surface = the_surface;
+      WinSetWindowPtr( handle, QWL_USER, surface );
+    }
+
+    switch( mess )
+    {
+    case WM_DESTROY:
+      /* warn the main thread to quit if it didn't know */
+      surface->event.type = gr_event_key;
+      surface->event.key  = grKeyEsc;
+      DosPostEventSem( surface->event_lock );
+      break;
+
+    case WM_CREATE:
+      /* set original magnification */
+      minimized = FALSE;
+
+      /* create Device Context and Presentation Space for screen. */
+      screen_dc = WinOpenWindowDC( handle );
+      screen_ps = GpiCreatePS( surface->anchor,
+                               screen_dc,
+                               &sizl,
+                               PU_PELS | GPIT_MICRO |
+                               GPIA_ASSOC | GPIF_DEFAULT );
+      /* take the input focus */
+      WinFocusChange( HWND_DESKTOP, handle, 0L );
+      LOG(( "screen_dc and screen_ps have been created\n" ));
+      break;
+
+    case WM_MINMAXFRAME:
+      /* to update minimized if changed */
+      swp = *((PSWP) parm1);
+      if ( swp.fl & SWP_MINIMIZE ) 
+        minimized = TRUE;
+      if ( swp.fl & SWP_RESTORE )
+        minimized = FALSE;
+      return WinDefWindowProc( handle, mess, parm1, parm2 );
+      break;
+
+    case WM_ERASEBACKGROUND:
+    case WM_PAINT:  
+      /* copy the memory image of the screen out to the real screen */
+      DosRequestMutexSem( surface->image_lock, SEM_INDEFINITE_WAIT );
+      WinBeginPaint( handle, screen_ps, NULL );
+      
+      /* main image and magnified picture */
+      GpiBitBlt( screen_ps,
+                 surface->image_ps,
+                 4L,
+                 surface->blit_points,
+                 ROP_SRCCOPY, BBO_AND );
+
+      WinEndPaint( screen_ps );
+      DosReleaseMutexSem( surface->image_lock );   
+      break;
+
+    case WM_HELP:  /* this really is a F1 Keypress !! */
+      surface->event.key = grKeyF1;
+      goto Do_Key_Event;
+
+    case WM_CHAR:
+      if ( CHARMSG( &mess )->fs & KC_KEYUP )
+        break;
+
+      /* look for a specific vkey */
+      {
+        int          count = sizeof( key_translators )/sizeof( key_translators[0] );
+        Translator*  trans = key_translators;
+        Translator*  limit = trans + count;
+
+        for ( ; trans < limit; trans++ )
+          if ( CHARMSG(&mess)->vkey == trans->os2key )
+          {
+            surface->event.key = trans->grkey;
+            goto Do_Key_Event;
+          }
+      }
+
+      /* otherwise, simply record the character code */
+      if ( (CHARMSG( &mess )->fs & KC_CHAR) == 0 )
+        break;
+
+      surface->event.key = CHARMSG(&mess)->chr;
+
+    Do_Key_Event:
+      surface->event.type = gr_event_key;
+      DosPostEventSem( surface->event_lock );
+      break;
+
+    default:
+      return WinDefWindowProc( handle, mess, parm1, parm2 );
+    }
+
+    return (MRESULT) FALSE;
+  }
+
+
+
+
+  grDevice  gr_os2pm_device =
+  {
+    sizeof( grPMSurface ),
+    "os2pm",
+    
+    init_device,
+    done_device,
+    
+    (grDeviceInitSurfaceFunc) init_surface,
+    
+    0,
+    0
+    
+  };
+
+
--- /dev/null
+++ b/demos/graph/os2/gros2pm.def
@@ -1,0 +1,5 @@
+NAME        WINDOWCOMPAT
+
+DESCRIPTION 'FreeType Graphics'
+HEAPSIZE    8192
+STACKSIZE   40888
--- /dev/null
+++ b/demos/graph/os2/gros2pm.h
@@ -1,0 +1,23 @@
+#ifndef GROS2PM_H
+#define GROS2PM_H
+
+#include "grobjs.h"
+
+  extern
+  grDevice  gr_os2pm_device;
+
+#ifdef GR_INIT_BUILD
+  static
+  grDeviceChain  gr_os2pm_device_chain =
+  {
+    "os2pm",
+    &gr_os2pm_device,
+    GR_INIT_DEVICE_CHAIN
+  };
+
+#undef GR_INIT_DEVICE_CHAIN
+#define GR_INIT_DEVICE_CHAIN  &gr_os2pm_device_chain
+
+#endif  /* GR_INIT_BUILD */
+
+#endif /* GROS2PM_H */
--- /dev/null
+++ b/demos/graph/os2/rules.mk
@@ -1,0 +1,32 @@
+#**************************************************************************
+#*
+#*  OS/2 specific rules file, used to compile the OS/2 graphics driver
+#*  to the graphics subsystem
+#*
+#**************************************************************************
+
+ifeq ($(PLATFORM),os2)
+
+GR_OS2  := $(GRAPH_)os2
+GR_OS2_ := $(GR_OS2)$(SEP)
+
+# the GRAPH_LINK is expanded each time an executable is linked with the
+# graphics library.
+#
+GRAPH_LINK     += $(GR_OS2_)gros2pm.def
+
+# Add the OS/2 driver object file to the graphics library "graph.a"
+#
+GRAPH_OBJS += $(OBJ_)gros2pm.$O
+
+DEVICES         += OS2_PM
+DEVICE_INCLUDES += $(GR_OS2)
+
+# the rule used to compile the graphics driver
+#
+$(OBJ_)gros2pm.$O: $(GR_OS2_)gros2pm.c $(GR_OS2_)gros2pm.h
+	$(CC) $(CFLAGS) $(GRAPH_INCLUDES:%=$I%) $I$(GR_OS2) $T$@ $<
+
+endif
+
+
--- a/demos/graph/rules.mk
+++ b/demos/graph/rules.mk
@@ -45,11 +45,11 @@
 #
 #
 
-GRAPH_INCLUDES := graph
-GRAPH_LIB      := $(OBJ_)graph.a
+GRAPH_INCLUDES := $(TOP2_)graph
+GRAPH_LIB      := $(OBJ_)graph.$A
 GRAPH_LINK     := $(GRAPH_LIB)
 
-GRAPH_ := graph$(SEP)
+GRAPH_ := $(TOP2_)graph$(SEP)
 
 GRAPH_H := $(GRAPH_)graph.h    \
            $(GRAPH_)grtypes.h  \
@@ -65,10 +65,15 @@
               $(OBJ_)grinit.$O
 
 
+# Default value for COMPILE_GRAPH_LIB
+# this value can be modified by the system-specific graphics drivers..
+#
+COMPILE_GRAPH_LIB = ar -r $@ $(GRAPH_OBJS)
+
 # Add the rules used to detect and compile graphics driver depending
 # on the current platform..
 #
-include $(wildcard config/*/rules.mk)
+include $(wildcard $(GRAPH_)/*/rules.mk)
 
 #########################################################################
 #
@@ -80,7 +85,7 @@
 #
 #
 $(GRAPH_LIB): $(GRAPH_OBJS)
-	ar -r $@ $(GRAPH_OBJS)
+	$(COMPILE_GRAPH_LIB)
 
 
 # pattern rule for normal sources
--- /dev/null
+++ b/demos/graph/win32/grwin32.c
@@ -1,0 +1,504 @@
+/*******************************************************************
+ *
+ *  grwin32.c  graphics driver for Win32 platform.              0.1
+ *
+ *  This is the driver for displaying inside a window under Win32,
+ *  used by the graphics utility of the FreeType test suite.
+ *
+ *  Written by Antoine Leca.
+ *  Copyright 1999-2000 by Antoine Leca, David Turner
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  Borrowing liberally from the other FreeType drivers.
+ *
+ *  This file is part of the FreeType project, and may only be used
+ *  modified and distributed under the terms of the FreeType project
+ *  license, LICENSE.TXT. By continuing to use, modify or distribute
+ *  this file you indicate that you have read the license and
+ *  understand and accept it fully.
+ *
+ ******************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include "grwin32.h"
+#include "grdevice.h"
+
+
+/* logging facility */
+#include <stdarg.h>
+
+#define  DEBUGxxx
+
+#ifdef DEBUG
+#define LOG(x)  LogMessage##x
+#else
+#define LOG(x)  /* rien */
+#endif
+
+#ifdef DEBUG
+  static void  LogMessage( const char*  fmt, ... )
+  {
+    va_list  ap;
+
+    va_start( ap, fmt );
+    vfprintf( stderr, fmt, ap );
+    va_end( ap );
+  }
+#endif
+/*-------------------*/
+
+/*  Size of the window. */
+#define WIN_WIDTH   640u
+#define WIN_HEIGHT  450u
+
+/* These values can be changed, but WIN_WIDTH should remain for now a  */
+/* multiple of 32 to avoid padding issues.                             */
+
+  typedef struct  _Translator
+  {
+    ULONG   winkey;
+	grKey   grkey;
+	
+  } Translator;
+  
+  static
+  Translator  key_translators[] =
+  {
+    { VK_BACK,      grKeyBackSpace },
+    { VK_TAB,       grKeyTab       },
+    { VK_RETURN,    grKeyReturn    },
+    { VK_ESCAPE,       grKeyEsc       },
+    { VK_HOME,      grKeyHome      },
+    { VK_LEFT,      grKeyLeft      },
+    { VK_UP,        grKeyUp        },
+    { VK_RIGHT,     grKeyRight     },
+    { VK_DOWN,      grKeyDown      },
+  /*
+    { VK_PAGEUP,    grKeyPageUp    },
+    { VK_PAGEDOWN,  grKeyPageDown  },
+   */
+    { VK_END,       grKeyEnd       },
+    { VK_F1,        grKeyF1        },
+    { VK_F2,        grKeyF2        },
+    { VK_F3,        grKeyF3        },
+    { VK_F4,        grKeyF4        },
+    { VK_F5,        grKeyF5        },
+    { VK_F6,        grKeyF6        },
+    { VK_F7,        grKeyF7        },
+    { VK_F8,        grKeyF8        },
+    { VK_F9,        grKeyF9        },
+    { VK_F10,       grKeyF10       },
+    { VK_F11,       grKeyF11       },
+    { VK_F12,       grKeyF12       }
+  };
+
+  /* This is a minimalist driver, it is only able to display */
+  /* a _single_ window. Moreover, only monochrome and gray   */
+  /* bitmaps are supported..                                 */
+  
+  /* handle of the window. */
+  static HWND   hwndGraphic;
+
+  static int window_width, window_height;
+
+  /* the following variables are used to set the window title lazily */
+  static int          title_set = 1;
+  static const char*  the_title;
+
+  /* bitmap information */
+  static LPBITMAPINFO pbmi;
+  static HBITMAP      hbm;
+
+  /* local event to pass on */
+  static grEvent  ourevent;
+  static int      eventToProcess = 0;
+
+/* destroys the surface*/
+static
+void done_surface( grSurface*  surface )
+{
+  /* The graphical window has perhaps already destroyed itself */
+  if ( hwndGraphic )
+  {
+    DestroyWindow ( hwndGraphic );
+    PostMessage( hwndGraphic, WM_QUIT, 0, 0 );
+  }
+  grDoneBitmap( &surface->bitmap );
+  if ( pbmi ) free ( pbmi );
+}
+
+  static
+  const int  pixel_mode_bit_count[] =
+  {
+    0,
+    1,   /* mono  */
+    4,   /* pal4  */
+    8,   /* pal8  */
+	8,   /* grays */
+    15,  /* rgb15 */
+    16,  /* rgb16 */
+    24,  /* rgb24 */
+    32   /* rgb32 */
+  };
+
+  static
+  void  refresh_rectangle( grSurface*  surface,
+  						   int         x,
+						   int		   y,
+						   int         w,
+						   int         h )
+  {
+    HDC     hDC;
+    int     row_bytes;
+
+    LOG(( "Win32: refresh_rectangle( %08lx, %d, %d, %d, %d )\n",
+           (long)surface, x, y, w, h ));
+    (void)x;
+    (void)y;
+    (void)w;
+    (void)h;
+
+    row_bytes = surface->bitmap.pitch;
+    if (row_bytes < 0) row_bytes = -row_bytes;
+    
+    if ( row_bytes*8 != pbmi->bmiHeader.biWidth * pbmi->bmiHeader.biBitCount )
+      pbmi->bmiHeader.biWidth  = row_bytes * 8 / pbmi->bmiHeader.biBitCount;
+
+    hDC = GetDC ( hwndGraphic );
+    SetDIBits ( hDC, hbm,
+                0,
+                surface->bitmap.rows,
+                surface->bitmap.buffer,
+                pbmi,
+                DIB_RGB_COLORS );
+                
+    ReleaseDC ( hwndGraphic, hDC );
+
+    ShowWindow( hwndGraphic, SW_SHOW );
+    InvalidateRect ( hwndGraphic, NULL, FALSE );
+    UpdateWindow ( hwndGraphic );
+  }
+
+  static
+  void set_title( grSurface* surface, const char* title )
+  {
+    (void)surface;
+    
+    /* the title will be set on the next listen_event, just */
+    /* record it there..                                    */
+    the_title = title;
+    title_set = 0;
+  }
+
+  static
+  void listen_event( grSurface*  surface,
+                     int         event_mask,
+                     grEvent*    grevent )
+  {
+    MSG  msg;
+    
+    (void)surface;
+    (void)event_mask;
+    
+    if ( hwndGraphic && !title_set )
+    {
+      SetWindowText( hwndGraphic, the_title );
+      title_set = 1;
+    }
+    
+    do
+    {
+      while ( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
+      {
+        TranslateMessage( &msg );
+        DispatchMessage( &msg );
+      }
+      if (!eventToProcess)
+        WaitMessage();
+    }
+    while (!eventToProcess);
+    
+    *grevent = ourevent;
+  }
+
+/*
+ * set graphics mode
+ * and create the window class and the message handling.
+ */
+
+/* Declarations of the Windows-specific functions that are below. */
+static BOOL RegisterTheClass ( void );
+static BOOL CreateTheWindow  ( int width, int height );
+
+static
+grSurface*  init_surface( grSurface*  surface,
+                          grBitmap*   bitmap )
+{
+  static RGBQUAD  black = {    0,    0,    0, 0 };
+  static RGBQUAD  white = { 0xFF, 0xFF, 0xFF, 0 };
+  
+  if( ! RegisterTheClass() ) return 0;  /* if already running, fails. */
+
+  /* find some memory for the bitmap header */
+  if ( (pbmi = malloc ( sizeof ( BITMAPINFO ) + sizeof ( RGBQUAD ) * 256 ) )
+                              /* 256 should really be 2 if not grayscale */
+             == NULL )
+    /* lack of memory; fails the process */
+    return 0;
+
+  LOG(( "Win32: init_surface( %08lx, %08lx )\n",
+        (long)surface, (long)bitmap ));
+
+  LOG(( "       -- input bitmap =\n" ));
+  LOG(( "       --   mode   = %d\n", bitmap->mode ));
+  LOG(( "       --   grays  = %d\n", bitmap->grays ));
+  LOG(( "       --   width  = %d\n", bitmap->width ));
+  LOG(( "       --   height = %d\n", bitmap->rows ));
+
+  /* create the bitmap - under Win32, we support all modes as the GDI */
+  /* handles all conversions automatically..                          */
+  if ( grNewBitmap( bitmap->mode,
+                    bitmap->grays,
+  			        bitmap->width,
+			        bitmap->rows,
+                    bitmap ) )
+    return 0;
+
+  LOG(( "       -- output bitmap =\n" ));
+  LOG(( "       --   mode   = %d\n", bitmap->mode ));
+  LOG(( "       --   grays  = %d\n", bitmap->grays ));
+  LOG(( "       --   width  = %d\n", bitmap->width ));
+  LOG(( "       --   height = %d\n", bitmap->rows ));
+
+  bitmap->pitch   = -bitmap->pitch;
+  surface->bitmap = *bitmap;
+
+  /* initialize the header to appropriate values */
+  memset( pbmi, 0, sizeof ( BITMAPINFO ) + sizeof ( RGBQUAD ) * 256 );
+
+  switch ( bitmap->mode )
+  {
+  case gr_pixel_mode_mono:
+    pbmi->bmiHeader.biBitCount = 1;
+    pbmi->bmiColors[0] = white;
+    pbmi->bmiColors[1] = black;
+    break;
+
+  case gr_pixel_mode_gray:
+    pbmi->bmiHeader.biBitCount = 8;
+    pbmi->bmiHeader.biClrUsed  = bitmap->grays;
+    {
+      int   count = bitmap->grays;
+      int   x;
+      RGBQUAD*  color = pbmi->bmiColors;
+      
+      for ( x = 0; x < count; x++, color++ )
+      {
+        color->rgbRed   =
+        color->rgbGreen =
+        color->rgbBlue  = (((count-x)*255)/count);
+        color->rgbReserved = 0;
+      }
+    }
+    break;
+
+  default:
+    free ( pbmi );
+    return 0;         /* Unknown mode */
+  }
+
+  pbmi->bmiHeader.biSize   = sizeof ( BITMAPINFOHEADER );
+  pbmi->bmiHeader.biWidth  = bitmap->width;
+  pbmi->bmiHeader.biHeight = bitmap->rows;
+  pbmi->bmiHeader.biPlanes = 1;
+
+  if( ! CreateTheWindow( bitmap->width, bitmap->rows ) )
+  {
+    free ( pbmi );
+    return 0;
+  }
+  
+  surface->done         = (grDoneSurfaceFunc) done_surface;
+  surface->refresh_rect = (grRefreshRectFunc) refresh_rectangle;
+  surface->set_title    = (grSetTitleFunc)    set_title;
+  surface->listen_event = (grListenEventFunc) listen_event;
+
+  return surface;
+}
+
+
+/* ---- Windows-specific stuff ------------------------------------------- */
+
+LRESULT CALLBACK Message_Process( HWND, UINT, WPARAM, LPARAM );
+
+static
+BOOL RegisterTheClass ( void )
+  {
+  WNDCLASS ourClass = {
+      /* UINT    style        */ 0,
+      /* WNDPROC lpfnWndProc  */ Message_Process,
+      /* int     cbClsExtra   */ 0,
+      /* int     cbWndExtra   */ 0,
+      /* HANDLE  hInstance    */ 0,
+      /* HICON   hIcon        */ 0,
+      /* HCURSOR hCursor      */ 0,
+      /* HBRUSH  hbrBackground*/ 0,
+      /* LPCTSTR lpszMenuName */ NULL,
+      /* LPCTSTR lpszClassName*/ "FreeTypeTestGraphicDriver"
+  };
+
+    ourClass.hInstance    = GetModuleHandle( NULL );
+    ourClass.hIcon        = LoadIcon(0, IDI_APPLICATION);
+    ourClass.hCursor      = LoadCursor(0, IDC_ARROW);
+    ourClass.hbrBackground= GetStockObject(BLACK_BRUSH);
+
+    return RegisterClass(&ourClass) != 0;  /* return False if it fails. */
+  }
+
+static
+BOOL CreateTheWindow ( int width, int height )
+  {
+    window_width  = width;
+    window_height = height;
+
+    if ( ! (hwndGraphic = CreateWindow(
+        /* LPCSTR lpszClassName;    */ "FreeTypeTestGraphicDriver",
+        /* LPCSTR lpszWindowName;   */ "FreeType Test Graphic Driver",
+        /* DWORD dwStyle;           */  WS_OVERLAPPED | WS_SYSMENU,
+        /* int x;                   */  CW_USEDEFAULT,
+        /* int y;                   */  CW_USEDEFAULT,
+        /* int nWidth;              */  width + 2*GetSystemMetrics(SM_CXBORDER),
+        /* int nHeight;             */  height+ GetSystemMetrics(SM_CYBORDER)
+                                              + GetSystemMetrics(SM_CYCAPTION),
+        /* HWND hwndParent;         */  HWND_DESKTOP,
+        /* HMENU hmenu;             */  0,
+        /* HINSTANCE hinst;         */  GetModuleHandle( NULL ),
+        /* void FAR* lpvParam;      */  NULL))
+       )
+         /*  creation failed... */
+         return 0;
+
+    return 1;
+  }
+
+  /* Message processing for our Windows class */
+LRESULT CALLBACK Message_Process( HWND handle, UINT mess,
+                                  WPARAM wParam, LPARAM lParam )
+  {
+
+    switch( mess )
+    {
+    case WM_DESTROY:
+        /* warn the main thread to quit if it didn't know */
+      ourevent.type  = gr_event_key;
+      ourevent.key   = grKeyEsc;
+      eventToProcess = 1;
+      hwndGraphic    = 0;
+      PostQuitMessage ( 0 );
+      DeleteObject ( hbm );
+      break;
+
+    case WM_CREATE:
+      {
+        HDC     hDC;
+
+        hDC = GetDC ( handle );
+        hbm = CreateDIBitmap (
+          /* HDC hdc;     handle of device context        */ hDC,
+          /* BITMAPINFOHEADER FAR* lpbmih;  addr.of header*/ &pbmi->bmiHeader,
+          /* DWORD dwInit;  CBM_INIT to initialize bitmap */ 0,
+          /* const void FAR* lpvBits;   address of values */ NULL,
+          /* BITMAPINFO FAR* lpbmi;   addr.of bitmap data */ pbmi,
+          /* UINT fnColorUse;      RGB or palette indices */ DIB_RGB_COLORS);
+        ReleaseDC ( handle, hDC );
+        break;
+      }
+
+    case WM_PAINT:
+      {
+      HDC     hDC, memDC;
+      HANDLE  oldbm;
+      PAINTSTRUCT ps;
+
+      hDC = BeginPaint ( handle, &ps );
+      memDC = CreateCompatibleDC(hDC);
+      oldbm = SelectObject(memDC, hbm);
+      BitBlt ( hDC, 0, 0, window_width, window_height, memDC, 0, 0, SRCCOPY);
+      ReleaseDC ( handle, hDC );
+      SelectObject ( memDC, oldbm );
+      DeleteObject ( memDC );
+      EndPaint ( handle, &ps );
+    }
+
+    case WM_KEYDOWN:
+      switch ( wParam )
+      {
+      case VK_ESCAPE:
+        ourevent.type  = gr_event_key;
+        ourevent.key   = grKeyEsc;
+        eventToProcess = 1;
+        break;
+
+      default:
+        /* lookup list of translated keys */
+        {
+          int          count = sizeof( key_translators )/sizeof( key_translators[0] );
+          Translator*  trans = key_translators;
+          Translator*  limit = trans + count;
+          for ( ; trans < limit; trans++ )
+            if ( wParam == trans->winkey )
+            {
+              ourevent.key = trans->grkey;
+              goto Do_Key_Event;
+            }
+        }
+      }
+
+    case WM_CHAR:
+      {
+        ourevent.key = wParam;
+        
+    Do_Key_Event:
+        ourevent.type  = gr_event_key;
+        eventToProcess = 1;
+      }
+      break;
+
+    default:
+       return DefWindowProc( handle, mess, wParam, lParam );
+    }
+
+    return 0;
+  }
+
+  static int init_device( void )
+  {
+    return 0;
+  }
+
+  static void done_device( void )
+  {
+  }
+
+  grDevice  gr_win32_device =
+  {
+    sizeof( grSurface ),
+    "win32",
+    
+    init_device,
+    done_device,
+    
+    (grDeviceInitSurfaceFunc) init_surface,
+    
+    0,
+    0
+  };
+
+
+/* End */
--- /dev/null
+++ b/demos/graph/win32/grwin32.h
@@ -1,0 +1,23 @@
+#ifndef GRWIN32_H
+#define GRWIN32_H
+
+#include "grobjs.h"
+
+  extern
+  grDevice  gr_win32_device;
+
+#ifdef GR_INIT_BUILD
+  static
+  grDeviceChain  gr_win32_device_chain =
+  {
+    "win32",
+    &gr_win32_device,
+    GR_INIT_DEVICE_CHAIN
+  };
+
+#undef GR_INIT_DEVICE_CHAIN
+#define GR_INIT_DEVICE_CHAIN  &gr_win32_device_chain
+
+#endif  /* GR_INIT_BUILD */
+
+#endif /* GRWIN32_H */
--- /dev/null
+++ b/demos/graph/win32/rules.mk
@@ -1,0 +1,49 @@
+#**************************************************************************
+#*
+#*  Win32 specific rules file, used to compile the Win32 graphics driver
+#*  to the graphics subsystem
+#*
+#**************************************************************************
+
+ifeq ($(PLATFORM),win32)
+
+GR_WIN32  := $(GRAPH_)win32
+GR_WIN32_ := $(GR_WIN32)$(SEP)
+
+# Add the Win32 driver object file to the graphics library "graph.a"
+#
+GRAPH_OBJS += $(OBJ_)grwin32.$O
+
+DEVICES         += WIN32
+DEVICE_INCLUDES += $(GR_WIN32)
+
+# the rule used to compile the graphics driver
+#
+$(OBJ_)grwin32.$O: $(GR_WIN32_)grwin32.c $(GR_WIN32_)grwin32.h
+	$(CC) $(CFLAGS) $(GRAPH_INCLUDES:%=$I%) $I$(GR_WIN32) $T$@ $<
+
+# Now update COMPILE_GRAPH_LIB according to the compiler used on Win32
+#
+ifeq ($(CC),gcc)   # test for GCC
+LINK              = $(CC) $T$@ $< $(FTLIB)
+COMMON_LINK       = $(LINK) $(COMMON_OBJ)
+GRAPH_LINK        = $(COMMON_LINK) $(GRAPH_LIB) -luser32 -lgdi32
+endif
+
+ifeq ($(CC),cl)    # test for Visual C++
+COMPILE_GRAPH_LIB = lib /nologo /out:$(GRAPH_LIB) $(GRAPH_OBJS)
+LINK              = cl /nologo /MD -o $@ $< $(FTLIB)
+COMMON_LINK       = $(LINK) $(COMMON_OBJ)
+GRAPH_LINK        = $(COMMON_LINK) $(GRAPH_LIB) user32.lib gdi32.lib
+endif
+
+ifeq ($(CC),lcc)  # test for LCC-Win32
+COMPILE_GRAPH_LIB = lcclib /out:$(subst /,\\,$(GRAPH_LIB)) $(subst /,\\,$(GRAPH_OBJS))
+GRAPH_LINK        = $(subst /,\\,$(GRAPH_LIB)) user32.lib gdi32.lib
+LINK_ROOT         = lcclnk -o $(subst /,\\,$@) $(subst /,\\,$<)
+LINK              = $(LINK_ROOT) $(subst /,\\,$(FTLIB))
+COMMON_LINK       = $(LINK_ROOT) $(subst /,\\,$(COMMON_OBJ)) $(subst /,\\,$(FTLIB))
+GRAPH_LINK        = $(LINK_ROOT) $(subst /,\\,$(COMMON_OBJ)) $(subst /,\\,$(GRAPH_LIB)) $(subst /,\\,$(FTLIB))
+endif
+endif
+
--- /dev/null
+++ b/demos/graph/x11/grx11.c
@@ -1,0 +1,936 @@
+#include "grx11.h"
+
+
+#ifdef TEST
+#include "grfont.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
+
+  static void Panic( const char* message )
+  {
+    fprintf( stderr, "%s", message );
+    exit(1);
+  }
+
+  typedef struct Translator
+  {
+    KeySym  xkey;
+    grKey   grkey;
+    
+  } Translator;
+  
+  static
+  Translator  key_translators[] =
+  {
+    { XK_BackSpace, grKeyBackSpace },
+    { XK_Tab,       grKeyTab       },
+    { XK_Return,    grKeyReturn    },
+    { XK_Escape,    grKeyEsc       },
+    { XK_Home,      grKeyHome      },
+    { XK_Left,      grKeyLeft      },
+    { XK_Up,        grKeyUp        },
+    { XK_Right,     grKeyRight     },
+    { XK_Down,      grKeyDown      },
+    { XK_Page_Up,   grKeyPageUp    },
+    { XK_Page_Down, grKeyPageDown  },
+    { XK_End,       grKeyEnd       },
+    { XK_Begin,     grKeyHome      },
+    { XK_F1,        grKeyF1        },
+    { XK_F2,        grKeyF2        },
+    { XK_F3,        grKeyF3        },
+    { XK_F4,        grKeyF4        },
+    { XK_F5,        grKeyF5        },
+    { XK_F6,        grKeyF6        },
+    { XK_F7,        grKeyF7        },
+    { XK_F8,        grKeyF8        },
+    { XK_F9,        grKeyF9        },
+    { XK_F10,       grKeyF10       },
+    { XK_F11,       grKeyF11       },
+    { XK_F12,       grKeyF12       }
+  };
+
+
+#ifdef TEST
+  
+#define grAlloc  malloc
+  
+#endif
+
+
+  static Display*  display;
+  static char*     displayname = "";
+
+  static Cursor  idle;
+  static Cursor  busy;
+
+#define MAX_PIXEL_MODES  32
+
+  typedef XPixmapFormatValues  XDepth;
+
+  static int           num_pixel_modes = 0;
+  static grPixelMode   pixel_modes[ MAX_PIXEL_MODES ];  
+  static XDepth        pixel_depth[ MAX_PIXEL_MODES ];
+
+  typedef struct grXSurface_
+  {
+    grSurface      root;
+    grBitmap       image;
+
+    Window         win;
+    Visual*        visual;
+    Colormap       colormap;
+    int            depth;
+    Bool           gray;
+    
+    GC             gc;
+    
+    XColor         color[256];   /* gray levels palette for 8-bit modes */
+    XImage*        ximage;
+
+    int            win_org_x;
+    int            win_org_y;
+    int            win_width;
+    int            win_height;
+    
+    int            image_width;
+    int            image_height;
+    
+  } grXSurface;
+
+
+
+
+  /* close a given window */
+  static
+  void  done_surface( grXSurface*  surface )
+  {
+    XUnmapWindow( display, surface->win );
+  }
+
+
+
+  /* close the device, i.e. the display connection */
+  static
+  void  done_device( void )
+  {
+    XCloseDisplay( display );
+  }
+
+
+
+  static
+  void add_pixel_mode( grPixelMode  pixel_mode,
+                       XDepth*      depth )
+  {
+    if ( num_pixel_modes >= MAX_PIXEL_MODES )
+      Panic( "X11.Too many pixel modes\n" );
+      
+    pixel_modes[ num_pixel_modes ] = pixel_mode;
+    pixel_depth[ num_pixel_modes ] = *depth;
+    
+    num_pixel_modes++;
+  }
+
+
+
+  static
+  int  init_device( void )
+  {
+    XDepth  dummy;
+  
+    XrmInitialize();
+    
+    display = XOpenDisplay( displayname );
+    if (!display)
+    {
+      return -1;
+     /* Panic( "Gr:error: cannot open X11 display\n" ); */
+    }
+      
+    idle = XCreateFontCursor( display, XC_left_ptr );
+    busy = XCreateFontCursor( display, XC_watch );
+    
+    num_pixel_modes = 0;
+    
+    /* always enable the 8-bit gray levels pixel mode                */
+    /* even if its display is emulated through a constrained palette */
+    /* or another color mode                                         */
+    dummy.depth          = 8;
+    dummy.bits_per_pixel = 8;
+    dummy.scanline_pad   = 8;
+    add_pixel_mode( gr_pixel_mode_gray, &dummy );
+
+    {
+      int          count;
+      XDepth*      format;
+      XDepth*      formats;
+      XVisualInfo  template;
+
+      formats = XListPixmapFormats( display, &count );
+      format  = formats;
+       
+#ifdef TEST
+      printf( "available pixmap formats\n" );
+      printf( "depth  pixbits  scanpad\n" );
+#endif
+       
+      while ( count-- > 0 )
+      {
+#ifdef TEST 
+        printf( " %3d     %3d      %3d\n",
+                format->depth,
+                format->bits_per_pixel,
+                format->scanline_pad );
+#endif
+      
+        if ( format->depth == 1 )
+          /* usually, this should be the first format */
+          add_pixel_mode( gr_pixel_mode_mono, format );
+          
+        else if ( format->depth == 8 )
+          add_pixel_mode( gr_pixel_mode_pal8, format );
+
+        /* note, the 32-bit modes return a depth of 24, and 32 bits per pixel */          
+        else if ( format->depth == 24 )
+        {
+          if ( format->bits_per_pixel == 24 )
+            add_pixel_mode( gr_pixel_mode_rgb24, format );
+            
+          else if ( format->bits_per_pixel == 32 )
+            add_pixel_mode( gr_pixel_mode_rgb32, format );
+        }
+          
+        else if ( format->depth == 16 )
+        {
+          int           count2;
+          XVisualInfo*  visuals;
+          XVisualInfo*  visual;
+
+          template.depth = format->depth;
+          visuals        = XGetVisualInfo( display,
+                                           VisualDepthMask,
+                                           &template,
+                                           &count2 );
+          visual = visuals;
+          
+          while ( count2-- > 0 )
+          {
+#ifdef TEST 
+            const char*  string = "unknown";
+            
+            switch (visual->class)
+            {
+              case TrueColor:   string = "TrueColor";    break;
+              case DirectColor: string = "DirectColor";  break;
+              case PseudoColor: string = "PseudoColor";  break;
+              case StaticGray : string = "StaticGray";   break;
+              case StaticColor: string = "StaticColor";  break;
+              case GrayScale:   string = "GrayScale";    break;
+            }
+
+            printf( ">   RGB %02x:%02x:%02x, colors %3d, bits %2d  %s\n",
+                    visual->red_mask,
+                    visual->green_mask,
+                    visual->blue_mask,
+                    visual->colormap_size,
+                    visual->bits_per_rgb,
+                    string );
+#endif
+            if ( visual->red_mask   == 0xf800 &&
+                 visual->green_mask == 0x07e0 &&
+                 visual->blue_mask  == 0x001f )
+              add_pixel_mode( gr_pixel_mode_rgb565, format );
+              
+            else if ( visual->red_mask   == 0x7c00 &&
+                      visual->green_mask == 0x03e0 &&
+                      visual->blue_mask  == 0x001f )
+              add_pixel_mode( gr_pixel_mode_rgb555, format );
+              
+            /* other 16-bit modes are ignored */  
+            visual++;
+          }
+          
+          XFree( visuals );
+        }
+        
+        format++;
+      }
+      
+      XFree( formats );
+    }
+    
+    gr_x11_device.num_pixel_modes = num_pixel_modes;
+    gr_x11_device.pixel_modes     = pixel_modes;
+    
+    return 0;
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+  static
+  void  convert_gray_to_pal8( grXSurface*  surface,
+                              int          x,
+                              int          y,
+                              int          w,
+                              int          h )
+  {
+    grBitmap*  target  = &surface->image;
+    grBitmap*  source  = &surface->root.bitmap;
+    byte*      write   = (byte*)target->buffer + y*target->pitch + x;
+    byte*      read    = (byte*)source->buffer + y*source->pitch + x;
+    XColor*    palette = surface->color;
+    
+    while (h > 0)
+    {
+      byte*  _write = write;
+      byte*  _read  = read;
+      byte*  limit  = _write + w;
+      
+      for ( ; _write < limit; _write++, _read++ )
+        *_write = (byte) palette[ *_read ].pixel;
+
+      write += target->pitch;
+      read  += source->pitch;
+      h--;
+    }
+  }
+
+
+  static
+  void  convert_gray_to_16( grXSurface*  surface,
+                            int          x,
+                            int          y,
+                            int          w,
+                            int          h )
+  {
+    grBitmap*  target  = &surface->image;
+    grBitmap*  source  = &surface->root.bitmap;
+    byte*      write   = (byte*)target->buffer + y*target->pitch + 2*x;
+    byte*      read    = (byte*)source->buffer + y*source->pitch + x;
+    XColor*    palette = surface->color;
+    
+    while (h > 0)
+    {
+      byte*  _write = write;
+      byte*  _read  = read;
+      byte*  limit  = _write + 2*w;
+      
+      for ( ; _write < limit; _write += 2, _read++ )
+        *(short*)_write = (short)palette[ *_read ].pixel;
+
+      write += target->pitch;
+      read  += source->pitch;
+      h--;
+    }
+  }
+
+
+  static
+  void  convert_gray_to_24( grXSurface*  surface,
+                            int          x,
+                            int          y,
+                            int          w,
+                            int          h )
+  {
+    grBitmap*  target  = &surface->image;
+    grBitmap*  source  = &surface->root.bitmap;
+    byte*      write   = (byte*)target->buffer + y*target->pitch + 3*x;
+    byte*      read    = (byte*)source->buffer + y*source->pitch + x;
+    
+    while (h > 0)
+    {
+      byte*  _write = write;
+      byte*  _read  = read;
+      byte*  limit  = _write + 3*w;
+      
+      for ( ; _write < limit; _write += 3, _read++ )
+      {
+        byte  color = *_read;
+        
+        _write[0] =
+        _write[1] =
+        _write[2] = color;
+      }
+
+      write += target->pitch;
+      read  += source->pitch;
+      h--;
+    }
+  }
+
+
+  static
+  void  convert_gray_to_32( grXSurface*  surface,
+                            int          x,
+                            int          y,
+                            int          w,
+                            int          h )
+  {
+    grBitmap*  target  = &surface->image;
+    grBitmap*  source  = &surface->root.bitmap;
+    byte*      write   = (byte*)target->buffer + y*target->pitch + 4*x;
+    byte*      read    = (byte*)source->buffer + y*source->pitch + x;
+    
+    while (h > 0)
+    {
+      byte*  _write = write;
+      byte*  _read  = read;
+      byte*  limit  = _write + 4*w;
+      
+      for ( ; _write < limit; _write += 4, _read++ )
+      {
+        byte  color = *_read;
+        
+        _write[0] =
+        _write[1] =
+        _write[2] =
+        _write[3] = color;
+      }
+
+      write += target->pitch;
+      read  += source->pitch;
+      h--;
+    }
+  }
+
+
+  static
+  void  convert_rectangle( grXSurface*  surface,
+                           int          x,
+                           int          y,
+                           int          w,
+                           int          h )
+  {
+    int  z;
+    
+    /* first of all, clip to the surface's area */
+    if ( x   >= surface->image.width ||
+         x+w <= 0                    ||
+         y   >= surface->image.rows  ||
+         y+h <= 0 )
+      return;
+ 
+    if ( x < 0 )
+    {
+      w += x;
+      x  = 0;
+    }
+ 
+    z = (x + w) - surface->image.width;
+    if (z > 0)
+      w -= z;
+      
+    z = (y + h) - surface->image.rows;
+    if (z > 0)
+      h -= z;
+      
+    /* convert the rectangle to the target depth for gray surfaces */
+    if (surface->gray)
+    {
+      switch (surface->depth)
+      {
+        case 8 : convert_gray_to_pal8( surface, x, y, w, h ); break;
+        case 16: convert_gray_to_16  ( surface, x, y, w, h ); break;
+        case 24: convert_gray_to_24  ( surface, x, y, w, h ); break;
+        case 32: convert_gray_to_32  ( surface, x, y, w, h ); break;
+      }
+    }
+  } 
+
+
+  static
+  void  refresh_rectangle( grXSurface*  surface,
+                           int          x,
+                           int          y,
+                           int          w,
+                           int          h )
+  {
+    if (surface->gray)
+      convert_rectangle( surface, x, y, w, h );
+    
+    XPutImage( display,
+               surface->win,
+               surface->gc,
+               surface->ximage,
+               x, y, x, y, w, h );
+  }
+
+  
+  static
+  void  set_title( grXSurface*  surface,
+                   const char*  title )
+  {
+    XStoreName( display, surface->win, title );
+  }
+
+
+
+  static
+  grKey  KeySymTogrKey( KeySym  key )
+  {
+    grKey        k;
+    int          count = sizeof(key_translators)/sizeof(key_translators[0]);
+    Translator*  trans = key_translators;
+    Translator*  limit = trans + count;
+
+    k = grKeyNone;
+
+    while ( trans < limit )
+    {
+      if ( trans->xkey == key )
+      {
+        k = trans->grkey;
+        break;
+      }
+      trans++;
+    }
+
+    return k;
+  }
+
+
+
+  static  
+  void  listen_event( grXSurface*  surface,
+                      int          event_mask,
+                      grEvent*     grevent )
+  {
+    static char     key_buffer[10];
+    static int      key_cursor = 0;
+    static int      key_number = 0;
+    static XEvent   x_event;
+           KeySym   key;
+
+    int             bool_exit;
+    grKey           grkey;
+
+    XComposeStatus  compose;
+
+    /* XXXX : For now, ignore the event mask, and only exit when */
+    /*        a key is pressed..                                 */
+    (void)event_mask;
+
+    bool_exit = key_cursor < key_number;
+
+    XDefineCursor( display, surface->win, idle );
+
+    while ( !bool_exit )
+    {
+      XNextEvent( display, &x_event );
+
+      switch ( x_event.type )
+      {
+      case KeyPress: 
+        key_number = XLookupString( &x_event.xkey,
+                                    key_buffer,
+                                    sizeof ( key_buffer ),
+                                    &key,
+                                    &compose );
+        key_cursor = 0;
+
+        if ( key_number == 0 ||
+             key > 512       )
+        {
+          /* this may be a special key like F1, F2, etc.. */
+          grkey = KeySymTogrKey(key);
+          if (grkey != grKeyNone)
+            goto Set_Key;  
+        }
+        else
+          bool_exit = 1;
+        break;
+
+      case MappingNotify:
+        XRefreshKeyboardMapping( &x_event.xmapping );
+        break;
+      
+      case Expose:
+        refresh_rectangle( surface,
+                           x_event.xexpose.x,
+                           x_event.xexpose.y,
+                           x_event.xexpose.width,
+                           x_event.xexpose.height );
+        break;
+
+      /* You should add more cases to handle mouse events, etc. */
+      }
+    }
+
+    XDefineCursor( display, surface->win, busy );
+    XFlush       ( display );
+
+    /* Now, translate the keypress to a grKey */
+    /* If this wasn't part of the simple translated keys, simply get the charcode */
+    /* from the character buffer                                                  */
+    grkey = grKEY(key_buffer[key_cursor++]);
+      
+  Set_Key:
+    grevent->type = gr_key_down;
+    grevent->key  = grkey;
+  }
+
+
+
+
+  grXSurface*  init_surface( grXSurface*  surface,
+                             grBitmap*    bitmap )
+  {
+    int        screen;
+    grBitmap*  image;
+    char       grays;
+    XDepth*    format;
+    int        image_depth;
+    
+    screen = DefaultScreen( display );
+    
+    surface->colormap = DefaultColormap( display, screen );
+    surface->depth    = DefaultDepth( display, screen );
+    surface->visual   = DefaultVisual( display, screen ); 
+
+    image  = &surface->image;
+
+    /* force the surface image depth to 1 if necessary */
+    /* as this should be supported by all windows      */
+    image_depth = surface->depth;
+    if (bitmap->mode == gr_pixel_mode_mono)
+      image_depth = 1;
+
+    grays = ( bitmap->mode == gr_pixel_mode_gray &&
+              bitmap->grays >= 2 );
+
+    surface->gray = grays;
+ 
+    /* copy dimensions */
+    image->width  = bitmap->width;
+    image->rows   = bitmap->rows;
+    image->mode   = bitmap->mode;
+    image->pitch  = 0;
+    image->grays  = 0;
+    image->buffer = 0;
+
+    /* find the supported format corresponding to the request */
+    format = 0;
+
+    if (grays)    
+    {
+      /* choose the default depth in case of grays rendering */
+      int  i;
+      for ( i = 0; i < num_pixel_modes; i++ )
+        if ( image_depth == pixel_depth[i].depth )
+        {
+          format = pixel_depth + i;
+          break;
+        }
+    }
+    else
+    {
+      /* otherwise, select the format depending on the pixel mode */
+      int  i;
+      
+      format = 0;
+      for ( i = 0; i < num_pixel_modes; i++ )
+        if ( pixel_modes[i] == bitmap->mode )
+        {
+          format = pixel_depth + i;
+          break;
+        }
+    }
+    
+    if (!format)
+    {
+      grError = gr_err_bad_argument;
+      return 0;
+    }
+
+
+    /* correct surface.depth. This is required because in the case    */
+    /* of 32-bits pixels, the value of "format.depth" is 24 under X11 */
+    if ( format->depth          == 24 &&
+         format->bits_per_pixel == 32 )
+      image_depth = 32;
+     
+    /* allocate surface image */
+    {
+      int  bits, over;
+
+      bits = image->width * format->bits_per_pixel;
+      over = bits % format->scanline_pad;
+          
+      if (over)
+        bits += format->scanline_pad - over;
+      
+      if (!grays)
+      {
+        image->width  = bits;
+        bitmap->width = bits;
+      }
+      image->pitch  = bits >> 3;
+    }
+
+    image->buffer = grAlloc( image->pitch * image->rows );
+    if (!image->buffer) return 0;
+
+    /* now, allocate a gray pal8 pixmap, only when we asked */
+    /* for an 8-bit pixmap                                  */
+    if ( grays )
+    {
+      /* pad pitch to 32 bits */
+      bitmap->pitch  = (bitmap->width + 3) & -4;
+      bitmap->buffer = grAlloc( bitmap->pitch * bitmap->rows );
+      if (!bitmap->buffer)
+        Panic( "grX11: could not allocate surface bitmap!\n" );
+    }
+    else  /* otherwise */
+    {
+      *bitmap = *image;
+    }
+
+    surface->root.bitmap = *bitmap;
+ 
+    /* Now create the surface X11 image */
+    surface->ximage = XCreateImage( display, 
+                                    surface->visual,
+                                    format->depth,
+                                    format->depth == 1 ? XYBitmap : ZPixmap,
+                                    0,
+                                    (char*)image->buffer,
+                                    image->width,
+                                    image->rows,
+                                    8,
+                                    0 );
+    if ( !surface->ximage )
+      Panic( "grX11: cannot create surface X11 image\n" );
+ 
+
+    /* allocate gray levels in the case of gray surface */
+    if ( grays )
+    {
+      XColor*  color = surface->color;
+      int      i;
+      
+      for ( i = 0; i < bitmap->grays; i++, color++ )
+      {
+        color->red   =
+        color->green =
+        color->blue  = 65535 - ( i * 65535 ) / bitmap->grays;
+  
+        if ( !XAllocColor( display, surface->colormap, color ) )
+          Panic( "ERROR: cannot allocate Color\n" );
+      }
+    }
+    else if ( image_depth == 1 )
+    {
+      surface->ximage->byte_order       = MSBFirst;
+      surface->ximage->bitmap_bit_order = MSBFirst;
+    }
+
+    {
+        XTextProperty         xtp;
+        XSizeHints            xsh;
+        XSetWindowAttributes  xswa;
+    
+        xswa.border_pixel     = BlackPixel( display, screen );
+        xswa.background_pixel = WhitePixel( display, screen );
+        xswa.cursor           = busy;
+    
+        xswa.event_mask = KeyPressMask | ExposureMask;
+    
+        surface->win = XCreateWindow( display,
+                                      RootWindow( display, screen ),
+                                      0,
+                                      0,
+                                      image->width,
+                                      image->rows,
+                                      10,
+                                      surface->depth,
+                                      InputOutput, 
+                                      surface->visual,
+                                      CWBackPixel | CWBorderPixel |
+                                        CWEventMask | CWCursor,
+                                      &xswa );
+    
+        XMapWindow( display, surface->win );
+ 
+        surface->gc = XCreateGC( display, RootWindow( display, screen ), 0L, NULL );
+        XSetForeground( display, surface->gc, xswa.border_pixel     );
+        XSetBackground( display, surface->gc, xswa.background_pixel );
+    
+    
+        /* make window manager happy :-) */
+        xtp.value    = (unsigned char*)"FreeType";
+        xtp.encoding = 31;
+        xtp.format   = 8;
+        xtp.nitems   = strlen( (char*)xtp.value );
+    
+        xsh.x = 0;
+        xsh.y = 0;
+    
+        xsh.width  = image->width;
+        xsh.height = image->rows;
+        xsh.flags  = (PPosition | PSize);
+        xsh.flags  = 0;
+    
+        XSetWMProperties( display, surface->win, &xtp, &xtp, NULL, 0, &xsh, NULL, NULL );
+    }
+    
+    surface->root.done         = (grDoneSurfaceFunc) done_surface;
+    surface->root.refresh_rect = (grRefreshRectFunc) refresh_rectangle;
+    surface->root.set_title    = (grSetTitleFunc)    set_title;
+    surface->root.listen_event = (grListenEventFunc) listen_event;
+    
+    convert_rectangle( surface, 0, 0, bitmap->width, bitmap->rows );
+    return surface;
+  }
+  
+
+
+
+  grDevice  gr_x11_device =
+  {
+    sizeof( grXSurface ),
+    "x11",
+    
+    init_device,
+    done_device,
+    
+    (grDeviceInitSurfaceFunc) init_surface,
+    
+    0,
+    0
+    
+  };
+
+#ifdef TEST
+
+typedef struct grKeyName
+{
+  grKey       key;
+  const char* name;
+
+} grKeyName;
+
+
+static
+const grKeyName  key_names[] =
+{
+  { grKeyF1,   "F1"  },
+  { grKeyF2,   "F2"  },
+  { grKeyF3,   "F3"  },
+  { grKeyF4,   "F4"  },
+  { grKeyF5,   "F5"  },
+  { grKeyF6,   "F6"  },
+  { grKeyF7,   "F7"  },
+  { grKeyF8,   "F8"  },
+  { grKeyF9,   "F9"  },
+  { grKeyF10,  "F10" },
+  { grKeyF11,  "F11" },
+  { grKeyF12,  "F12" },
+  { grKeyEsc,  "Esc" },
+  { grKeyHome, "Home" },
+  { grKeyEnd,  "End"  },
+    
+  { grKeyPageUp,   "Page_Up" },
+  { grKeyPageDown, "Page_Down" },
+  { grKeyLeft,     "Left" },
+  { grKeyRight,    "Right" },
+  { grKeyUp,       "Up" },
+  { grKeyDown,     "Down" },
+  { grKeyBackSpace, "BackSpace" },
+  { grKeyReturn,   "Return" }
+};
+
+int  main( void )
+{
+  grSurface*  surface;
+  int         n;
+  
+  grInit();
+  surface = grNewScreenSurface( 0, gr_pixel_mode_gray, 320, 400, 128 );
+  if (!surface)
+    Panic("Could not create window\n" );
+  else
+  {
+    grColor      color;
+    grEvent      event;
+    const char*  string;
+    int          x;
+    
+    grSetSurfaceRefresh( surface, 1 );
+    grSetTitle(surface,"X11 driver demonstration" );
+    
+    for ( x = -10; x < 10; x++ )
+    {
+      for ( n = 0; n < 128; n++ )
+      {
+        color.value = (n*3) & 127;
+        grWriteCellChar( surface,
+                         x + ((n % 60) << 3),
+                         80 + (x+10)*8*3 + ((n/60) << 3), n, color );
+      }
+
+    }
+    color.value = 64;
+    grWriteCellString( surface, 0, 0, "just an example", color );
+    
+    do
+    {
+      listen_event((grXSurface*)surface, 0, &event);
+    
+      /* return if ESC was pressed */
+      if ( event.key == grKeyEsc )
+        return 0;
+      
+      /* otherwise, display key string */
+      color.value = (color.value + 8) & 127;
+      {
+        int         count = sizeof(key_names)/sizeof(key_names[0]);
+        grKeyName*  name  = key_names;
+        grKeyName*  limit = name + count;
+        const char* kname  = 0;
+        char        kname_temp[16];
+      
+        while (name < limit)
+        {
+          if ( name->key == event.key )
+          {
+            kname = name->name;
+            break;
+          }
+          name++;
+        }
+      
+        if (!kname)
+        {
+          sprintf( kname_temp, "char '%c'", (char)event.key );
+          kname = kname_temp;
+        }
+        
+        grWriteCellString( surface, 30, 30, kname, color );
+        grRefreshSurface(surface);
+        paint_rectangle( surface, 0, 0, surface->bitmap.width, surface->bitmap.rows );
+      }
+    } while (1);
+  }
+    
+  return 0;
+  
+  
+}
+#endif /* TEST */
+
--- /dev/null
+++ b/demos/graph/x11/grx11.h
@@ -1,0 +1,24 @@
+#ifndef GRX11_H
+#define GRX11_H
+
+#include "grobjs.h"
+#include "grdevice.h"
+
+  extern
+  grDevice  gr_x11_device;
+
+#ifdef GR_INIT_BUILD
+  static
+  grDeviceChain  gr_x11_device_chain =
+  {
+    "x11",
+    &gr_x11_device,
+    GR_INIT_DEVICE_CHAIN
+  };
+
+#undef GR_INIT_DEVICE_CHAIN
+#define GR_INIT_DEVICE_CHAIN  &gr_x11_device_chain
+
+#endif  /* GR_INIT_BUILD */
+
+#endif /* GRX11_H */
--- /dev/null
+++ b/demos/graph/x11/rules.mk
@@ -1,0 +1,81 @@
+#**************************************************************************
+#*
+#*  X11-specific rules files, used to compile the X11 graphics driver
+#*  when supported by the current platform
+#*
+#**************************************************************************
+
+#########################################################################
+#
+# Try to detect an X11 setup.
+#
+# We simply try to detect a `X11R6/bin', `X11R5/bin' or `X11/bin' in
+# the current path.
+#
+ifneq ($(findstring X11R6$(SEP)bin,$(PATH)),)
+xversion := X11R6
+else
+
+ifneq ($(findstring X11R5$(SEP)bin,$(PATH)),)
+xversion := X11R5
+else
+
+ifneq ($(findstring X11$(SEP)bin,$(PATH)),)
+xversion := X11
+endif
+endif
+endif
+
+ifdef xversion
+X11_PATH := $(subst ;, ,$(PATH)) $(subst :, ,$(PATH))
+X11_PATH := $(filter %$(xversion)$(SEP)bin,$(X11_PATH))
+X11_PATH := $(X11_PATH:%$(SEP)bin=%)
+endif
+
+##########################################################################
+#
+# Update some variables to compile the X11 graphics module. Note that
+# X11 is available on Unix, or on OS/2. However, it only compiles with
+# gcc on the latter platform, which is why it is safe to use the flags
+# `-L' and `-l'
+#
+ifneq ($(X11_PATH),)
+
+X11_INCLUDE    := $(X11_PATH:%=%$(SEP)include)
+X11_LIB        := $(X11_PATH:%=%$(SEP)lib)
+
+# the GRAPH_LINK variable is expanded each time an executable is linked against
+# the graphics library..
+#
+GRAPH_LINK     += $(X11_LIB:%=-L%) -lX11
+
+# Solaris needs a -lsocket in GRAPH_LINK ..
+#
+UNAME := $(shell uname)
+ifneq ($(findstring $(UNAME),SunOS Solaris),)
+GRAPH_LINK += -lsocket
+endif
+
+
+# add the X11 driver object file to the graphics library
+#
+GRAPH_OBJS += $(OBJ_)grx11.$O
+
+
+
+GR_X11  := $(GRAPH_)x11
+GR_X11_ := $(GR_X11)$(SEP)
+
+DEVICES         += X11
+DEVICE_INCLUDES += $(GR_X11)
+
+# the rule used to compile the X11 driver
+#
+$(OBJ_)grx11.$O: $(GR_X11_)grx11.c $(GR_X11_)grx11.h
+	$(CC) $(CFLAGS) $(GRAPH_INCLUDES:%=$I%) $I$(GR_X11) \
+              $(X11_INCLUDE:%=$I%) $T$@ $<
+endif
+
+
+
+