/**
 *
 * ChoX11: XLib replacement for RISC OS
 *
 * ChoX11 core functonality
 *
 * Copyright 2003 by Peter Naulls
 * Written by Peter Naulls
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation. No representations are made about the suitability of this
 * software for any purpose.  It is provided "as is" without express or
 * implied warranty.
 *
 */

#define XLIB_ILLEGAL_ACCESS
#define NeedFunctionPrototypes 1
#define NeedNestedPrototypes   1

#include <X11/Xlib.h> 
#include <X11/Xatom.h>
#include "Xatomtype.h"

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
#include <fcntl.h>

#include "chox11.h"


/* Cause UnixLib to use a DA for its heap
const char *__dynamic_da_name = "ChoX11 Heap"; */

/* Set application variables*/
const char *Chox11_application_name;



/* Reference to the single display.  X Supports multiple displays
   but we only implement display 0 */
Display *Chox11_display;
XDrawable Chox11_root_window = { True };

XDrawable **Chox11_drawable_list;
int Chox11_drawable_num;
int Chox11_drawable_max;

Chox_Font *Chox11_basefont;

/* Pixel translation table for plotting pixmaps to the screen */
void *Chox11_ScreenPixTrans;

/* The keyboard */
static XKeyboardState Chox11_keyboard;


int Chox11_ConvertBppToBytes(int bpp) {
  int width = sizeof(char);

  /* Sprite files use bytes, half words and full words */
  if (bpp <= 8) return width;
  if (bpp <= 16) return 2 * width;

  return 4 * width;
}


/**
 * Update a display's screen settings to reflect the current RISC OS desktop
 * mode.
 */
static void Chox11_UpdateScreenInfo(Display *display) {

  Screen_CacheModeInfo(); /* get current mode settings read */

  display->screens->root_depth = 32 /*screen_bpp*/;
  display->screens->width  = screen_size.x >> screen_eig.x;
  display->screens->height = screen_size.y >> screen_eig.y;

  /* Set up pixel translation */
  if (Chox11_ScreenPixTrans) {
    free(Chox11_ScreenPixTrans);
    Chox11_ScreenPixTrans = NULL;
  }  
}


XDrawable *Chox11_FindWindow(window_handle window) {
  int find;

  Fortify_CheckAllMemory();

  /* Start at 1 - zero is the root window, and doesn't have a
     valid handle */
  for (find = 1; find < Chox11_drawable_num; find++) {
    XDrawable *draw = Chox11_drawable_list[find];

    if (draw->isWindow && draw->data.window.handle == window) {
      return draw;
    }
  }

  return NULL;
}


Bool Chox11_FindDrawable(XDrawable *entry) {
  int find;

  /* Start at 1 - zero is the root window, and doesn't have a valid handle */
  for (find = 1; find < Chox11_drawable_num; find++) {
    if (Chox11_drawable_list[find] == entry) return True;
  }

  return False;
}


void Chox11_AddDrawable(XDrawable *drawable) {

  printf("Chox11_AddDrawable: Adding drawable %x to list\n",
         (int)drawable);

  if (Chox11_drawable_num == Chox11_drawable_max) {
    Chox11_drawable_max *= 2;
    /* TODO: NULL check */
    Chox11_drawable_list = realloc(Chox11_drawable_list,
                              sizeof(XDrawable *) * Chox11_drawable_max);
    assert(Chox11_drawable_list);
    printf("drawable max now: %d\n", Chox11_drawable_max);
  }

  Chox11_drawable_list[Chox11_drawable_num++] = drawable;
}


extern XModifierKeymap *XDeleteModifiermapEntry(

    XModifierKeymap*	 modmap,
    unsigned int	 keycode_entry,
    int			 modifier

) {
  printf("XModifierKeymap\n");
  return NULL;
}


extern XModifierKeymap	*XGetModifierMapping(

    Display*		 display

) {
  XModifierKeymap *ptr = calloc(sizeof(XModifierKeymap), 1);

  printf("XGetModifierMapping: returned id = %x\n", (int)ptr);
  return ptr;
}


extern XModifierKeymap	*XInsertModifiermapEntry(

    XModifierKeymap*	 modmap,
    unsigned int	 keycode_entry,
    int			 modifier

) {
  printf("XInsertModifiermapEntry (not implemented)\n");
  return NULL;
}

extern XModifierKeymap *XNewModifiermap(

    int			 max_keys_per_mod

);



extern Display *XOpenDisplay(

    _Xconst char*	 display_name

) {
   Display *display = calloc(sizeof(Display), 1);

   Chox11Debug_Init();

   display->fd = open("/dev/null", O_RDWR); 

   display->screens = calloc(sizeof(Screen), 1);
   display->screens->display = display;   
   display->screens->root = (Window)&Chox11_root_window;

   display->vendor = (char *)"Native RISC OS X-Windows Interface";

   Chox11_UpdateScreenInfo(display);
   atexit(Chox11Image_FreeImages);

   {
     Visual *visual = calloc(sizeof(Visual), 1);
   
     visual->visualid     = 1;
     visual->class        = TrueColor;
     visual->red_mask     = 0x000000ff;
     visual->green_mask   = 0x0000ff00;
     visual->blue_mask    = 0x00ff0000;
     visual->bits_per_rgb = 8;
     visual->map_entries  = 256;
   
     display->screens->root_visual = visual;
   }
   
   display->screens->white_pixel = 0x00ffffff;
   display->screens->black_pixel = 0x00000000;

   {
       Chox11_Colormap *cm = calloc(sizeof(Chox11_Colormap),1);
       cm->type = TrueColor;
       display->screens->cmap = (Colormap)cm;
   }

   /* default screen context */
   display->screens->default_gc = calloc(sizeof(struct _XGC), 1);
   {
      XGContext *context;

      context = calloc(sizeof(XGContext), 1);
      assert(context);

      context->values.function    = GXcopy;
      context->values.foreground = display->screens->black_pixel;
      context->values.background = display->screens->white_pixel;

      display->screens->default_gc->gid = (GContext)context;
   }

   {
     ScreenFormat *formats = calloc(sizeof(ScreenFormat), 2);

     formats[0].depth          = 32;
     formats[0].bits_per_pixel = 32;
     formats[0].scanline_pad   = 32;

     formats[1].depth          = 24;
     formats[1].bits_per_pixel = 32;
     formats[1].scanline_pad   = 32;

     display->pixmap_format = formats;
     display->nformats = 2;
   }

   Chox11_display = display;
   
   Chox11_root_window.data.window.parent.draw = &Chox11_root_window;
   
   Chox11_EventInitialise(X_APP_NAME);

   /* Initialise internal databases */
   Chox11DB_InitContexts();
   Chox11DB_InitProperties();
   
   Chox11_drawable_max = 4;
   Chox11_drawable_list = malloc(sizeof(XDrawable *) * Chox11_drawable_max);
   Chox11_drawable_num = 1;
   Chox11_drawable_list[0] = &Chox11_root_window;
   
   Screen_CacheModeInfo();

   /* Base font for GC default.  Initial count of 1, so it is never discarded */
   Chox11_basefont =
     (Chox_Font *)XLoadFont(display, "-*-helvetica-medium-*-*--16-*-*-*-*-*-*"); /* Default for now */

   if (Chox11_basefont == (Chox_Font *)BadName) {
     fprintf(stderr, "ChoX11: Could not load base font\n");
     return NULL;
   }

   Chox11Font_AddRef(Chox11_basefont);

   return display;
}


extern char *XFetchBytes(

    Display*		 display,
    int*		 nbytes_return

) {
  puts("XFetchBytes (not implemented)");

  *nbytes_return = 0;
  return NULL;
}


extern char *XFetchBuffer(

    Display*		 display,
    int*		 nbytes_return,
    int			 buffer

) {
  puts("XFetchBuffer (not implemented)");
  *nbytes_return = 0;
  return NULL;
}



extern Status XGetAtomNames(

    Display*		 dpy,
    Atom*		 atoms,
    int			 count,
    char**		 names_return

) {
  puts("XGetAtomNames (not implemented)");

  *names_return = strdup("atom");
  return 0;
}


extern char *XDisplayName(

    _Xconst char*	 string

) {
  return strdup(string ? string : "ChoX11");
}

extern int (*XSynchronize(

    Display*		 display,
    Bool		 onoff

))() {
  puts("XSynchronize");

  /* doesn't really apply to ChoX11 */
  return 0;
}



extern int (*XSetAfterFunction(

    Display*		 display,
    int (*procedure) (
#if NeedNestedPrototypes
	     Display*	 display
#endif
            )		

))() {
  puts("XSetAfterFunction (not implemented)");
  return 0;
}

extern Window XCreateSimpleWindow(

    Display*		 display,
    Window		 parent,
    int			 x,
    int			 y,
    unsigned int	 width,
    unsigned int	 height,
    unsigned int	 border_width,
    unsigned long	 border,
    unsigned long	 background

) {
  XDrawable *window = calloc(sizeof(XDrawable), 1);
  window_block block;
  BOOL topLevel;
  int bw;
  XDrawable *pwindow = (XDrawable *)parent;
  XEvent *event;

  if (border_width > 100) border_width = 0;
  window->data.window.border_width = bw = border_width * 2;
  window->data.window.border       = border;

  printf("XCreateSimpleWindow %d %d %d %d %d %d\n",
         x, y, width, height, bw, background);

  printf("window = %p %p\n", window, parent);

  /* Check allocation. Check valid parent */

  if (parent == (Window)&Chox11_root_window) {
    puts("parent is root");

    topLevel = True;
  } else {
    printf("parent is not root: %p\n", parent);
    topLevel = False;
  }

  pwindow->data.window.children.draw =
          realloc(pwindow->data.window.children.draw,
                 (pwindow->data.window.nchildren + 1) * sizeof(XDrawable *));
  pwindow->data.window.children.draw[pwindow->data.window.nchildren++] = window;

  window->data.window.x      = x;
  window->data.window.y      = y;
  window->width  = width;
  window->height = height;

  block.screenrect.min.x = x * 2;
  block.screenrect.min.y = screen_size.y - (y + height) * 2 - 2 * bw - 2;
  block.screenrect.max.x = (x + width) * 2 + 2 * bw;
  block.screenrect.max.y = screen_size.y - y * 2 - 2;
  block.scroll.x = 0;
  block.scroll.y = 0;
  printf("window (x0,y0, x1,y1) = %i,%i, %i,%i\n", block.screenrect.min.x,
   block.screenrect.min.y, block.screenrect.max.x, block.screenrect.max.y); 

  block.behind = -1;

  block.flags.value = 0;
  block.flags.data.realcolours = 1;
  if (topLevel) {
    block.flags.data.moveable    = 1;
    block.flags.data.open        = 1;
    block.flags.data.backicon    = 1;
    block.flags.data.closeicon   = 1;
    block.flags.data.titlebar    = 1;
    block.flags.data.vscroll     = 1;
    block.flags.data.ignorebottom = 1;
    block.flags.data.adjusticon  = 1;
  }
  block.flags.data.newflags    = 1;

  ((int *)&block.colours)[0] = topLevel ? 0xff070207 : 0xffffffff;
  ((int *)&block.colours)[1] = 0x000c0103;
                                                  
  block.workarearect.min.x = 0;
  block.workarearect.min.y = -height * 2 - bw * 2;
  block.workarearect.max.x = width * 2 + bw * 2;
  block.workarearect.max.y = 0;

  block.titleflags.value = 0x2700013d;
  block.workflags.value = 0x3000;  
  block.spritearea = (void *)-1;
  
  block.minsize.x = 1;
  block.minsize.y = 1;
  
  block.title.indirecttext.buffer = calloc(X_WIN_TITLE_BUFFER, 1);
  assert(block.title.indirecttext.buffer != NULL);
  block.title.indirecttext.bufflen = X_WIN_TITLE_BUFFER;
  strncpy(block.title.indirecttext.buffer, X_WIN_TITLE, X_WIN_TITLE_BUFFER - 1);
  block.title.indirecttext.validstring = NULL;

  block.numicons = 0;

  Wimp_CreateWindow(&block, &window->data.window.handle);
  printf("createsimplewindow: created new window, handle = 0x%X\n",
          window->data.window.handle);

  window->isWindow                = True;
  window->data.window.isMapped    = False;
  window->data.window.visibility  = VisibilityFullyObscured;
  window->data.window.parent.ref  = parent;
  window->data.window.background  = background;
  window->data.window.cursor      = None;

  Chox11_AddDrawable(window);

  if ((event = Chox11_CreateMapNotifyEvent(display, window, CreateNotify))) {
    event->xcreatewindow.parent            = parent;
    event->xcreatewindow.window            = (Window)window;
    event->xcreatewindow.x                 = x;
    event->xcreatewindow.y                 = y;
    event->xcreatewindow.width             = width;
    event->xcreatewindow.height            = height;
    event->xcreatewindow.border_width      = border_width;
    event->xcreatewindow.override_redirect = False; /* TODO */

    Chox11_EventWindowUnset();
  }

  return (Window)window;
}


extern Window XCreateWindow(

    Display*		 display,
    Window		 parent,
    int			 x,
    int			 y,
    unsigned int	 width,
    unsigned int	 height,
    unsigned int	 border_width,
    int			 depth,
    unsigned int	 class,
    Visual*		 visual,
    unsigned long	 valuemask,
    XSetWindowAttributes*	 attributes

)
{
   XDrawable *window;

   printf("XCreateWindow: calling XCreateSimpleWindow. class=%i\n",
          class);

   /* Need to check window for errors */
   window = (XDrawable *)XCreateSimpleWindow(display, parent, x, y,
                                             width, height, border_width,
                                             0, 0);

   XChangeWindowAttributes(display, (Window)window, valuemask, attributes);

   printf("XCreateWindow: event_mask: %x %x\n",
          valuemask & CWEventMask,
          window->data.window.event_mask);

   return (Window)window;
}


extern Window XGetSelectionOwner(

    Display*		 display,
    Atom		 selection

) {
  puts("XGetSelectionOwner (not implemented)");
  return None;
}


extern char **XListExtensions(

    Display*		 display,
    int*		 nextensions_return

);
extern Atom *XListProperties(

    Display*		 display,
    Window		 w,
    int*		 num_prop_return

);
extern XHostAddress *XListHosts(

    Display*		 display,
    int*		 nhosts_return,
    Bool*		 state_return

);
extern KeySym XKeycodeToKeysym(

    Display*		 display,
#if NeedWidePrototypes
    unsigned int	 keycode,
#else
    KeyCode		 keycode,
#endif
    int			 index

);

extern KeySym *XGetKeyboardMapping(

    Display*		 display,
#if NeedWidePrototypes
    unsigned int	 first_keycode,
#else
    KeyCode		 first_keycode,
#endif
    int			 keycode_count,
    int*		 keysyms_per_keycode_return

) {
  puts("XGetKeyboardMapping (not implemented)");
  *keysyms_per_keycode_return = keycode_count;
  return calloc(sizeof(KeySym), 1);
}


extern char *XScreenResourceString(

	Screen*		 screen

) {
    Atom prop_name;
    Atom actual_type;
    int actual_format;
    unsigned long nitems;
    unsigned long leftover;
    char *val = NULL;

    prop_name = XInternAtom(screen->display, "SCREEN_RESOURCES", True);
    if (prop_name &&
	XGetWindowProperty(screen->display, screen->root, prop_name,
			   0L, 100000000L, False,
			   XA_STRING, &actual_type, &actual_format,
			   &nitems, &leftover,
			   (unsigned char **) &val) == Success) {
	if ((actual_type == XA_STRING) && (actual_format == 8))
	    return val;
	if (val)
	    free(val);
    }
    return NULL;
}


/* multithread routines */

extern Status XInitThreads(

    void

);

extern void XLockDisplay(

    Display*		 display

);

extern void XUnlockDisplay(

    Display*		 display

);

/* routines for dealing with extensions */

extern XExtCodes *XInitExtension(

    Display*		 display,
    _Xconst char*	 name

) {
  puts("XInitExtension (not implemented)");
  return NULL;
}

extern XExtCodes *XAddExtension(

    Display*		 display

) {
  puts("XAddExtension (not implemented)");
  return calloc(1, sizeof(XExtCodes));
}


extern XExtData *XFindOnExtensionList(

    XExtData**		 structure,
    int			 number

);
extern XExtData **XEHeadOfExtensionList(

    XEDataObject	 object

);


extern unsigned long XNextRequest(

    Display*		 display

) {
  puts("XNextRequest (not implemented)");
  return 0;
}


extern Status XReconfigureWMWindow(

    Display*		 display,
    Window		 w,
    int			 screen_number,
    unsigned int	 mask,
    XWindowChanges*	 changes

);


extern Status XWithdrawWindow(

    Display*		 display,
    Window		 w,
    int			 screen_number

) {
  puts("XWithdrawWindow (not implemented)");
  return 0;
}



/* The following are given in alphabetical order */

extern XAddHost(

    Display*		 display,
    XHostAddress*	 host

);

extern XAddHosts(

    Display*		 display,
    XHostAddress*	 hosts,
    int			 num_hosts    

);

extern XAddToExtensionList(

    struct _XExtData**	 structure,
    XExtData*		 ext_data

);


extern XBell(

    Display*		 display,
    int			 percent

) {
  puts("XBell (not implemented)");
}


extern XChangeActivePointerGrab(

    Display*		 display,
    unsigned int	 event_mask,
    Cursor		 cursor,
    Time		 time

) {
 puts("XChangeActivePointerGrab (not implemented)");
}


extern XChangeKeyboardControl(

    Display*		 display,
    unsigned long	 value_mask,
    XKeyboardControl*	 values

) {
 printf("XChangeKeyboardControl: not implemented\n");
}

extern XChangeKeyboardMapping(

    Display*		 display,
    int			 first_keycode,
    int			 keysyms_per_keycode,
    KeySym*		 keysyms,
    int			 num_codes

);

extern XChangePointerControl(

    Display*		 display,
    Bool		 do_accel,
    Bool		 do_threshold,
    int			 accel_numerator,
    int			 accel_denominator,
    int			 threshold

);

extern XChangeProperty(

    Display*		 display,
    Window		 w,
    Atom		 property,
    Atom		 type,
    int			 format,
    int			 mode,
    _Xconst unsigned char*	 data,
    int			 nelements

) {
  XProperty *entry;
  char *name;
  int ret = BadValue;

  printf("XChangeProperty: window = %x, property = %x, format = %d,"
         " type = %x, data = %p,%d\n",
         w, property, format, type, data, nelements);
  if(type == XA_STRING) printf("XChangeProperty: data = '%s'\n", data); 

  /* Perform limited checks on passed data */
  if ((name = XGetAtomName(display, property)) == NULL) {
    printf("XChangeProperty: Returning BadAtom\n");
    fflush(stdout);
    return BadAtom;
  }

  printf("XChangeProperty: name = %s\n", name);

  switch (mode) {
    case PropModeReplace:
      printf("XChangeProperty: PropModeReplace\n");
      entry = Chox11DB_PropertyFind(w, property, type);
      if (entry == NULL)
      {
        printf("XChangeProperty: property doesn't exist, creating new one\n");
        ret = Chox11DB_PropertyAdd(w, property, type, format, mode, data, nelements);
      }
      else
      {
        printf("XChangeProperty: replacing existing entry %p\n", entry);
        ret = 0;
        Chox11DB_PropertyReplace(entry, data);
      }
      break;

    /* TODO: Actually perform correct action */
    case PropModePrepend:
      printf("XChangeProperty: PropModePrepend - not implemented\n");
    case PropModeAppend:
      printf("XChangeProperty: PropModeAppend - not implemented\n");
      entry = Chox11DB_PropertyFind(w, property, type);
      if (entry == NULL)
        return Chox11DB_PropertyAdd(w, property, type, format, mode, data,
                                   nelements); 
      break;
  }

  // Process properties that have an effect
  if (ret == 0) {
    switch(property) {
      case XA_WM_NAME:
        {
           XDrawable *window = (XDrawable *)w;
           //TODO: Check w is valid
           if (window->isWindow) {
             if (window->data.window.parent.ref == (Window)&Chox11_root_window
               && type == XA_STRING) {
               Window_SetTitle(window->data.window.handle, data);
             }
           } else ret = BadWindow;
        }
        break;
    } 
  }
  
  return ret;
}

extern XChangeWindowAttributes(

    Display*		 display,
    Window		 w,
    unsigned long	 valuemask,
    XSetWindowAttributes*  attributes

) {
  XDrawable *window = (XDrawable *)w;

  printf("XChangeWindowAttributes:  %p %x\n", w, valuemask);

  if (attributes) {
    if (valuemask & CWBackPixmap)
      printf("Setting pixmap not implemented\n");
    if (valuemask & CWBackPixel)
      window->data.window.background = attributes->background_pixel;
    if (valuemask & CWBorderPixel)
      window->data.window.border     = attributes->border_pixel;

    if (valuemask & CWBitGravity)
      printf("Setting bit gravity not implemented\n");
    if (valuemask & CWWinGravity)
      printf("Setting win gravity not implemented\n");

    if (valuemask & (CWBackingStore | CWBackingPlanes | CWBackingPixel)) {
      /* Don't support backing store, but may need to store the setting */
    }

    if (valuemask & CWOverrideRedirect)
      window->data.window.override = attributes->override_redirect;
    if (valuemask & CWSaveUnder)
      printf("Setting saveunder not implemented\n");

    if (valuemask & CWEventMask)
      window->data.window.event_mask = attributes->event_mask;

    if (valuemask & CWDontPropagate)
      window->data.window.no_propagate = attributes->do_not_propagate_mask;
    if (valuemask & CWColormap)
      printf("Setting color map not implemented\n");

    if (valuemask & CWCursor)
      window->data.window.cursor = attributes->cursor;
  }
}


extern XCirculateSubwindows(

    Display*		 display,
    Window		 w,
    int			 direction

);

extern XCirculateSubwindowsDown(

    Display*		 display,
    Window		 w

);

extern XCirculateSubwindowsUp(

    Display*		 display,
    Window		 w

);

extern XCloseDisplay(

    Display*		 display

) {
 puts("XCloseDisplay (not implemented)");
}


extern XConfigureWindow(

    Display*		 display,
    Window		 w,
    unsigned int	 value_mask,
    XWindowChanges*	 values		 

) {
  XDrawable *window = (XDrawable *)w;

  printf("XConfigureWindow: %x values:%x\n", w, value_mask);

  if (value_mask & CWX)
    window->data.window.x = values->x;

  if (value_mask & CWY)
    window->data.window.y = values->y;

  if (value_mask & CWWidth)
    window->width = values->width;

  if (value_mask & CWHeight)
    window->height = values->height;

  if (value_mask & CWBorderWidth)
    window->data.window.border_width = values->border_width;

/*  if (value_mask & CWSibling)

  if (value_mask & CWStackMode)*/

  /* Reshow the window with new values */
  if (window->data.window.isOpen) {
    /* TODO - This isn't correct - we need a separate reopen function */
    window->data.window.isMapped = False;
    XMapWindow(display, w);
  }

  Chox11_CreateConfigureNotifyEvent(display, window);
}

extern XConvertSelection(

    Display*		 display,
    Atom		 selection,
    Atom 		 target,
    Atom		 property,
    Window		 requestor,
    Time		 time

) {
  puts("XConvertSelection (not implemented)");
}


extern XCopyPlane(

    Display*		 display,
    Drawable		 src,
    Drawable		 dest,
    GC			 gc,
    int			 src_x,
    int			 src_y,
    unsigned int	 width,
    unsigned int	 height,
    int			 dest_x,
    int			 dest_y,
    unsigned long	 plane

) {
  puts("XCopyPlane (not implemented)");
}


extern XDeleteProperty(

    Display*		 display,
    Window		 w,
    Atom		 property

) {
  printf("XDeleteProperty (not implemented): w=%x, property=%x\n", w, property);
}


Bool Chox11_RemoveDrawable(XDrawable *rdraw)
{
  int find;

  printf("remove drawable: %p\n", rdraw);

  for (find = 1; find < Chox11_drawable_num; find++) {
    XDrawable *draw = Chox11_drawable_list[find];

    if (draw == rdraw) {
      /* Ensure it has no queued graphics */
      Chox11Queue_EmptyFor(draw);

      memmove(Chox11_drawable_list + find, Chox11_drawable_list + find + 1,
              (Chox11_drawable_num - find - 1) * sizeof(XDrawable *));
      Chox11_drawable_num--;
      return True;        
    }
  }
  return False;
}



extern XDestroyWindow(

    Display*		 display,
    Window		 w

) {
  XDrawable *window = (XDrawable *)w;

  printf("XDestroyWindow: %x\n", w);

  if (Chox11_RemoveDrawable(window)) {
    Window_Delete(window->data.window.handle);
    if (window->gcinfo.clip_sprite != NULL) free(window->gcinfo.clip_sprite);
    if (window->gcinfo.clip_rects != NULL) Chox11ClipRects_Release(window->gcinfo.clip_rects);
    free(window);
  }
}


extern XDestroySubwindows(

    Display*		 display,
    Window		 w

);


#undef XDestroyImage
void XDestroyImage(XImage *image);

extern XFree(

    void*		 data

) {  
  printf("XFree: Freeing %p\n", data);

  if (data) {
    /* This checks to see if it's an image, and destroys its
       extra data.  If not, it just frees it */
    XDestroyImage(data);
  }
}

extern XFreeExtensionList(

    char**		 list    

);

extern XFreeModifiermap(

    XModifierKeymap*	 modmap

) {
  free(modmap);
}



extern Status XGetGeometry(

    Display*		 display,
    Drawable		 d,
    Window*		 root_return,
    int*		 x_return,
    int*		 y_return,
    unsigned int*	 width_return,
    unsigned int*	 height_return,
    unsigned int*	 border_width_return,
    unsigned int*	 depth_return

) {
  XDrawable *drawable = (XDrawable *)d;

  printf("XGetGeometry %p\n", d);


  if (drawable->isWindow) {
    *root_return = (Window)&Chox11_root_window;

    if (d == (Window)&Chox11_root_window) {
      *x_return      = 0;
      *y_return      = 0;
      *width_return  = screen_size.x / 2;
      *height_return = screen_size.y / 2;
      *border_width_return = 0;

    } else {
      /* Internal co-ordinates are kept up to data in Open window event */
      *x_return = drawable->data.window.x;
      *y_return = drawable->data.window.y;
      *width_return = drawable->width;
      *height_return = drawable->height;
      *border_width_return = drawable->data.window.border_width/2;
    }

    *depth_return = 32; /* Screen is always treated as 32 bits per pixel */

  } else {
    sprite_areainfo *sarea = &drawable->data.image.pixmap;
    sprite_info info;

    Sprite_ReadInfo(sarea, X_SPRITE_NAME, &info);

    *root_return = (Drawable)&Chox11_root_window;
    *x_return = 0;
    *y_return = 0;
    *width_return  = info.width;
    *height_return = info.height;
    *border_width_return = 0;
    *depth_return = 32;
    if (info.mode.sprite_mode.type == 0) *depth_return = 1;
  }

  return 0;
}


extern XGetInputFocus(

    Display*		 display,
    Window*		 focus_return,
    int*		 revert_to_return) {

  puts("XGetInputFocus (not implemented)");

  *focus_return = None;
  *revert_to_return = RevertToNone;

  return Success;
}

extern XGetKeyboardControl(

    Display*		 display,
    XKeyboardState*	 values_return

) {
  puts("XGetKeyboardControl");

  values_return = &Chox11_keyboard;
}

extern XGetPointerControl(

    Display*		 display,
    int*		 accel_numerator_return,
    int*		 accel_denominator_return,
    int*		 threshold_return

);

extern int XGetPointerMapping(

    Display*		 display,
    unsigned char*	 map_return,
    int			 nmap

);

extern XGetScreenSaver(

    Display*		 display,
    int*		 timeout_return,
    int*		 interval_return,
    int*		 prefer_blanking_return,
    int*		 allow_exposures_return

);

extern int XGetWindowProperty(

    Display*		 display,
    Window		 w,
    Atom		 property,
    long		 long_offset,
    long		 long_length,
    Bool		 delete,
    Atom		 req_type,
    Atom*		 actual_type_return,
    int*		 actual_format_return,
    unsigned long*	 nitems_return,
    unsigned long*	 bytes_after_return,
    unsigned char**	 prop_return

) {
  printf("XGetWindowProperty (not implemented): w=%x, property=%x, delete=%x\n",
       w, property, delete);

  *actual_type_return = None;
  *actual_format_return = 0;
  *bytes_after_return = 0;
  *nitems_return = 0;

  return 0;
}

extern Status XGetWindowAttributes(

    Display*		 display,
    Window		 w,
    XWindowAttributes*	 window_attributes_return

) {
  XDrawable *draw = (XDrawable *)w;

  printf("XGetWindowAttributes: %p\n", draw);

  memset(window_attributes_return, 0, sizeof(XWindowAttributes));

  if (w == (Window)&Chox11_root_window) {
    window_attributes_return->x      = 0;
    window_attributes_return->y      = 0;
    window_attributes_return->width  = screen_size.x / 2;
    window_attributes_return->height = screen_size.y / 2;

  } else {
    window_attributes_return->x      = draw->data.window.x;
    window_attributes_return->y      = draw->data.window.y;
    window_attributes_return->width  = draw->width;
    window_attributes_return->height = draw->height;

  }

  /* TODO */
  window_attributes_return->border_width = draw->data.window.border_width;
  window_attributes_return->depth        = 8;

  window_attributes_return->visual = display->screens->root_visual;
  window_attributes_return->root   = draw->data.window.parent.dref;

  window_attributes_return->class  = 0;

  /* TODO: more */

  window_attributes_return->do_not_propagate_mask = draw->data.window.no_propagate;
  window_attributes_return->screen = display->screens;

  printf("%d %d\n", window_attributes_return->width,
                    window_attributes_return->height); 

  return IsViewable;
}

extern XGrabButton(

    Display*		 display,
    unsigned int	 button,
    unsigned int	 modifiers,
    Window		 grab_window,
    Bool		 owner_events,
    unsigned int	 event_mask,
    int			 pointer_mode,
    int			 keyboard_mode,
    Window		 confine_to,
    Cursor		 cursor

) {
  puts("XGrabButton (not implemented)");
}


extern XGrabKey(

    Display*		 display,
    int			 keycode,
    unsigned int	 modifiers,
    Window		 grab_window,
    Bool		 owner_events,
    int			 pointer_mode,
    int			 keyboard_mode
) {
  puts("XGrabKey (not implemented)");
}

extern int XGrabKeyboard(

    Display*		 display,
    Window		 grab_window,
    Bool		 owner_events,
    int			 pointer_mode,
    int			 keyboard_mode,
    Time		 time

) {
  puts("GrabKeyboard (not implemented)");
  return GrabSuccess;
}


extern XGrabServer(

    Display*		 display

) {
  puts("XGrabServer (not implemented)");
}


extern XKillClient(

    Display*		 display,
    XID			 resource

);

extern XLowerWindow(

    Display*		 display,
    Window		 w

) {
  puts("XLowerWindow (not implemented)");
  Chox11_CreateConfigureNotifyEvent(display, (XDrawable *)w);
}


extern XMapRaised(

    Display*		 display,
    Window		 w

) {
  puts("XMapRaised (not implemented - passing on to XMapWindow)");
  ((XDrawable *)w)->data.window.isMapped = False;
  XMapWindow(display, w);
  Chox11_CreateConfigureNotifyEvent(display, (XDrawable *)w);
}

/* Remove scroll bars from a window */
static void MakeFixedWindow(XDrawable *window) {
  window_info info;

  /* Get current window definition */
  Window_GetInfo3(window->data.window.handle, &info);

  if (info.block.flags.data.vscroll) {
    /* Delete the current window */
    Window_Delete(window->data.window.handle);

    /* Remove the vscroll, adjust and title icon */
    info.block.flags.data.vscroll    = 0;
    info.block.flags.data.adjusticon = 0;
    info.block.flags.data.titlebar   = 0;
    /* Remove border */
    info.block.colours[0]            = 0xff;

    /* Re-create window with new settings */
    Wimp_CreateWindow(&info.block, &window->data.window.handle);
  }
}

extern XMapWindow(

    Display*		 display,
    Window		 w

) {
  XDrawable *window = (XDrawable *)w;
  XEvent *event;
  window_state state;
  XProperty *prop;
  BOOL parentRoot;

  if (window->data.window.isMapped)
    return;

  printf("XMapWindow: opening window 0x%X\n", window->data.window.handle);

  prop = Chox11DB_PropertyFind(w, XA_WM_NORMAL_HINTS, XA_WM_SIZE_HINTS);
  parentRoot = (window->data.window.parent.draw == &Chox11_root_window);

  {
    int px, py;
    int bw = window->data.window.border_width;
     window_openblocknest nest;

    if (parentRoot) {
      px = 0;
      py = screen_size.y; 
    } else {
      int pbw = window->data.window.parent.draw->data.window.border_width;

      Wimp_GetWindowState(window->data.window.parent.draw->data.window.handle,
                          &state);

      px = state.openblock.screenrect.min.x + pbw;
      py = state.openblock.screenrect.max.y - pbw;
      printf("pbw %d\n", pbw);
    }

    printf("px: %d py %d\n", px, py);
    printf("override = %d\n", window->data.window.override);

    if (prop && window->data.window.override) {
      xPropSizeHints *hints = (xPropSizeHints *)prop->data;

      if (hints->flags & PPosition) {
        printf("hints set (pos): %d %d\n", hints->x, hints->y);
        window->data.window.x = hints->x;
        window->data.window.y = hints->y;
      }
      if (hints->flags & PSize)
        printf("hints set (size): %d %d\n", hints->width, hints->height);
      if (hints->flags & USPosition)
        printf("hints set (uspos): %d %d\n", hints->x, hints->y);
      if (hints->flags & USSize)
        printf("hints set (ussize): %d %d\n", hints->width, hints->height);
      if (hints->flags & PMinSize)
        printf("hints set (minsize): %d %d\n", hints->minWidth, hints->minHeight);
      if (hints->flags & PMaxSize)
        printf("hints set (maxsize): %d %d\n", hints->maxWidth, hints->maxHeight);

      if (parentRoot 
          && (hints->flags & PMinSize) && (hints->flags & PMaxSize)
          && hints->minWidth == hints->maxWidth
          && hints->minHeight == hints->maxHeight) {
             MakeFixedWindow(window);
             window->width = hints->minWidth;
             window->height = hints->minHeight;
          }
    }

    nest.openblock.window = window->data.window.handle;

    printf("%d %d %d %d\n",
           window->data.window.x,
           window->data.window.y,
           window->width,
           window->height);

    if (parentRoot && !window->data.window.override) {
      printf("opening centred\n");
      Window_Show(window->data.window.handle, open_CENTERED);
    } else {
  
      nest.openblock.screenrect.min.x =
        px + window->data.window.x * 2;
      nest.openblock.screenrect.min.y =
        py - (window->data.window.y + window->height) * 2 - bw * 2;
      nest.openblock.screenrect.max.x =
        px + (window->data.window.x + window->width) * 2 + bw * 2;
      nest.openblock.screenrect.max.y =
        py - window->data.window.y * 2;
  
      printf("subwindow: %d %d %d %d\n",
           nest.openblock.screenrect.min.x,
           nest.openblock.screenrect.min.y,
           nest.openblock.screenrect.max.x,
           nest.openblock.screenrect.max.y);
  
      nest.openblock.scroll.x = 0;
      nest.openblock.scroll.y = 0;
      nest.openblock.behind   = -1;
      nest.flags.value        = 0;
  
      /* Attached to parent. */
      if (parentRoot) {
        Wimp_OpenWindow(&nest.openblock);
      } else {
        Wimp_OpenWindowNest(&nest, window->data.window.parent.draw->data.window.handle, FALSE);
      }
    }

    /* Update to actual positions */
    Wimp_GetWindowState(window->data.window.handle, &state);
    Chox11_UpdateWindowPos(window, &state.openblock);
 }

  if ((event = Chox11_CreateMapNotifyEvent(display, window, MapNotify))) {
/*    event->xmap.event             = window->data.window.parent.ref;*/
    event->xmap.window            = w;
    event->xmap.override_redirect = False; /* TODO */

/*    Chox11_EventWindowUnset();*/
  }

  Chox11_CreateVisibilityEvent(Chox11_display, (Window)window,
                               VisibilityUnobscured);
  window->data.window.visibility = VisibilityUnobscured;
  
  Chox11_CreateConfigureNotifyEvent(Chox11_display, window); 
}


extern XMapSubwindows(

    Display*		 display,
    Window		 w

) {
  XDrawable *window = (XDrawable *)w;
  int map;

  printf("XMapSubwindows: %p %d\n", window, window->data.window.nchildren);

  for (map = 0; map < window->data.window.nchildren; map++) {
    XMapWindow(display, window->data.window.children.ref[map]);
  }
}



extern XMoveResizeWindow(

    Display*		 display,
    Window		 w,
    int			 x,
    int			 y,
    unsigned int	 width,
    unsigned int	 height

) {
  XDrawable *window = (XDrawable *)w;
  window_info info;
  XDrawable *parent = window->data.window.parent.draw;
  int bw = window->data.window.border_width;

  printf("XMoveResizeWindow %d %d %d %d\n", x, y, width, height);

  Window_SetExtent(window->data.window.handle, 0, height * -2 -2 * bw, 32767, 0);

  Window_GetInfo3(window->data.window.handle, &info);

  if (parent == &Chox11_root_window) {
    info.block.screenrect.min.x = x * 2;
    info.block.screenrect.max.y = screen_size.y - y * 2;
  } else {
    convert_block coords;
    Window_GetCoords(parent->data.window.handle, &coords);
    info.block.screenrect.min.x = Coord_XToScreen(x*2, &coords);
    info.block.screenrect.max.y = Coord_YToScreen(-y*2, &coords);    
  }
  info.block.screenrect.max.x = info.block.screenrect.min.x + width * 2 + bw * 2;
  info.block.screenrect.min.y = info.block.screenrect.max.y - height * 2 - bw * 2;

  Wimp_OpenWindow((window_openblock *)&info);
  Chox11_UpdateWindowPos(window, (window_openblock *)&info);

  Chox11_CreateConfigureNotifyEvent(display, window);
}

extern XMoveWindow(

    Display*		 display,
    Window		 w,
    int			 x,
    int			 y

) {
  XDrawable *window = (XDrawable *)w;
  XDrawable *parent = window->data.window.parent.draw;
  window_info info;
  int width, height;

  printf("XMoveWindow: %x %d %d\n", w, x, y);

  Window_GetInfo3(window->data.window.handle, &info);

  width = info.block.screenrect.max.x - info.block.screenrect.min.x;
  height = info.block.screenrect.max.y - info.block.screenrect.min.y;

  if (parent == &Chox11_root_window) {
    info.block.screenrect.min.x = x * 2;
    info.block.screenrect.max.y = screen_size.y - y * 2;
  } else {
    convert_block coords;
    Window_GetCoords(parent->data.window.handle, &coords);
    info.block.screenrect.min.x = Coord_XToScreen(x*2, &coords);
    info.block.screenrect.max.y = Coord_YToScreen(-y*2, &coords);    
  }

  info.block.screenrect.max.x = info.block.screenrect.min.x + width;
  info.block.screenrect.min.y = info.block.screenrect.max.y - height;

  Wimp_OpenWindow((window_openblock *)&info);
  Chox11_UpdateWindowPos(window, (window_openblock *)&info);
}

extern XNoOp(

    Display*		 display

) {
}



extern Status XQueryBestSize(

    Display*		 display,
    int			 class,
    Drawable		 which_screen,
    unsigned int	 width,
    unsigned int	 height,
    unsigned int*	 width_return,
    unsigned int*	 height_return

);

extern Status XQueryBestStipple(

    Display*		 display,
    Drawable		 which_screen,
    unsigned int	 width,
    unsigned int	 height,
    unsigned int*	 width_return,
    unsigned int*	 height_return

);

extern Status XQueryBestTile(

    Display*		 display,
    Drawable		 which_screen,
    unsigned int	 width,
    unsigned int	 height,
    unsigned int*	 width_return,
    unsigned int*	 height_return

);

extern Bool XQueryExtension(

    Display*		 display,
    _Xconst char*	 name,
    int*		 major_opcode_return,
    int*		 first_event_return,
    int*		 first_error_return

) {
  puts("XQueryExtension (not implemented)");
  return False;
}

extern XQueryKeymap(

    Display*		 display,
    char 		 keys_return[32]

) {
  puts("XQueryKeymap: not supported");
  memset(keys_return, 0, sizeof(keys_return));
}

extern Status XQueryTree(

    Display*		 display,
    Window		 w,
    Window*		 root_return,
    Window*		 parent_return,
    Window**		 children_return,
    unsigned int*	 nchildren_return

) {
  XDrawable *window = (XDrawable *)w;
  Window *children = NULL;

  printf("XQueryTree %p\n");

  *root_return      = (Window)&Chox11_root_window;
  *parent_return    = window->data.window.parent.ref;

  *nchildren_return = window->data.window.nchildren;
  if (*nchildren_return) {
    children = calloc(*nchildren_return, sizeof(Window));
    if (children) {
      int child;
      for (child = 0; child < *nchildren_return; child++) {
        children[child] = window->data.window.children.ref[child];
      }
    }
  }

  *children_return  = children;

  return 0;
}

extern XRaiseWindow(

    Display*		 display,
    Window		 w

) {
  XDrawable *window = (XDrawable *)w;

  puts("XRaiseWindow: TODO - events (not implemented)");

  if (window->data.window.isMapped) {
    Window_BringToFront(window->data.window.handle);
  }
  Chox11_CreateConfigureNotifyEvent(display, window);
}

extern XRefreshKeyboardMapping(

    XMappingEvent*	 event_map    

) {
  puts("XRefreshKeyboardMapping (not implemented)");
}

extern XRemoveHost(

    Display*		 display,
    XHostAddress*	 host

);

extern XRemoveHosts(

    Display*		 display,
    XHostAddress*	 hosts,
    int			 num_hosts

);

extern XReparentWindow(

    Display*		 display,
    Window		 w,
    Window		 parent,
    int			 x,
    int			 y

) {
 puts("XReparentWindow (not implemented)");
}


extern XResizeWindow(

    Display*		 display,
    Window		 w,
    unsigned int	 width,
    unsigned int	 height

) {
  XDrawable *window = (XDrawable *)w;
  int border_width = window->data.window.border_width;
  window_info info;

  printf("XResizeWindow: %x %d %d\n",
                         window->data.window.handle, width, height);

  Window_GetInfo3(window->data.window.handle, &info);

  info.block.screenrect.max.x = info.block.screenrect.min.x + width * 2 + border_width * 2;
  info.block.screenrect.min.y = info.block.screenrect.max.y - height * 2 - border_width * 2;

  Window_SetExtent(window->data.window.handle,
                   0,
                   info.block.screenrect.min.y - info.block.screenrect.max.y,
                   32767,
                   0
                   );

  Wimp_OpenWindow((window_openblock *)&info);

  Chox11_UpdateWindowPos(window, (window_openblock *)&info);
  Chox11_CreateConfigureNotifyEvent(display, window);
}

extern XRestackWindows(

    Display*		 display,
    Window*		 windows,
    int			 nwindows

) {
  puts("XRestackWindows - not implemented");
//  Chox11_CreateConfigureNotifyEvent(display, window);
}

extern XRotateBuffers(

    Display*		 display,
    int			 rotate

) {
  puts("XRotateBuffers (not implemented)");

  return Success;
}

extern XRotateWindowProperties(

    Display*		 display,
    Window		 w,
    Atom*		 properties,
    int			 num_prop,
    int			 npositions

);

extern XSetCloseDownMode(

    Display*		 display,
    int			 close_mode

) {
 puts("XSetCloseDownMode (not implemented)");
}


extern XSetInputFocus(

    Display*		 display,
    Window		 focus,
    int			 revert_to,
    Time		 time

) {
  puts("XSetInputFocus (not implemented)");
}


extern int XSetModifierMapping(

    Display*		 display,
    XModifierKeymap*	 modmap

);


extern int XSetPointerMapping(

    Display*		 display,
    _Xconst unsigned char*	 map,
    int			 nmap

);

extern XSetScreenSaver(

    Display*		 display,
    int			 timeout,
    int			 interval,
    int			 prefer_blanking,
    int			 allow_exposures

);

extern XSetSelectionOwner(

    Display*		 display,
    Atom	         selection,
    Window		 owner,
    Time		 time

) {
  puts("XSetSelectionOwner (not implemented)");
}

extern XSetSubwindowMode(

    Display*		 display,
    GC			 gc,
    int			 subwindow_mode

) {
  puts("XSetSubwindowMode (not implemented)");
}


extern XSetWindowBackground(

    Display*		 display,
    Window		 w,
    unsigned long	 background_pixel

) {
  XDrawable *window = (XDrawable *)w;

  window->data.window.background = background_pixel;
}

extern XSetWindowBackgroundPixmap(

    Display*		 display,
    Window		 w,
    Pixmap		 background_pixmap

) {
  printf("XSetWindowBackgroundPixmap %p (not implemented)\n", (void *)background_pixmap);
}

extern XSetWindowBorder(

    Display*		 display,
    Window		 w,
    unsigned long	 border_pixel

) {
  puts("XSetWindowBorder (not implemented)");
}


extern XSetWindowBorderPixmap(

    Display*		 display,
    Window		 w,
    Pixmap		 border_pixmap

) {
  puts("XSetWindowBorderPixmap (not implemented)");
}

extern XSetWindowBorderWidth(

    Display*		 display,
    Window		 w,
    unsigned int	 width

) {
  puts("XSetWindowBorderWidth (not implemented)");
  Chox11_CreateConfigureNotifyEvent(display, (XDrawable *)w);
}

extern XStoreBuffer(

    Display*		 display,
    _Xconst char*	 bytes,
    int			 nbytes,
    int			 buffer

);

extern XStoreBytes(

    Display*		 display,
    _Xconst char*	 bytes,
    int			 nbytes

) {
 puts("XStoreBytes (not implemented)");
}

extern XSync(

    Display*		 display,
    Bool		 discard

) {
  Chox11_CallWimpPoll();
}


extern Bool XTranslateCoordinates(

    Display*		 display,
    Window		 src_w,
    Window		 dest_w,
    int			 src_x,
    int			 src_y,
    int*		 dest_x_return,
    int*		 dest_y_return,
    Window*		 child_return

) {
  XDrawable *src = (XDrawable *)src_w;
  XDrawable *dest = (XDrawable *)dest_w;
  XDrawable *pos;
  int abs_x = 0, abs_y = 0;

  printf("XTranslateCoordinates %p %p %d %d ", src, dest, src_x, src_y);

  if (!Chox11Debug_CheckWindow(src_w) && !Chox11Debug_CheckWindow(dest_w)) {
    /* TODO: Generate BadWindow here */
    return False;
  }

  /* Get absolute position of the destination window */
  pos = dest;
  while (pos != &Chox11_root_window) {
    abs_x += pos->data.window.x + pos->data.window.border_width / 2;
    abs_y += pos->data.window.y + pos->data.window.border_width / 2;
    printf("dest: %d %d\n", abs_x, abs_y);
    pos = pos->data.window.parent.draw;
  }

  /* Now subtract the position of the source, and get the difference */
  pos = src;
  while (pos != &Chox11_root_window) {
    abs_x -= pos->data.window.x + pos->data.window.border_width / 2;
    abs_y -= pos->data.window.y + pos->data.window.border_width / 2;
    printf("src: %d %d\n", abs_x, abs_y);
    pos = pos->data.window.parent.draw;
  }

  *dest_x_return = src_x - abs_x;
  *dest_y_return = src_y - abs_y;

  printf("%d %d\n", *dest_x_return, *dest_y_return);

  /* Now check to see if that's inside the destination window and it's
     a mapped subwindow  */
  *child_return = None;
  if (dest->data.window.parent.draw == src && dest->data.window.isMapped) {
    if (*dest_x_return >= 0 && *dest_x_return < dest->width &&
        *dest_y_return >= 0 && *dest_y_return < dest->height) {
      *child_return = dest_w;
    }
  }

  return True;
}

extern XUngrabButton(

    Display*		 display,
    unsigned int	 button,
    unsigned int	 modifiers,
    Window		 grab_window

) {
  puts("XUngrabButton (not implemented)");
}

extern XUngrabKey(

    Display*		 display,
    int			 keycode,
    unsigned int	 modifiers,
    Window		 grab_window

) {
  puts("XUngrabKey (not implemented)");
}

extern XUngrabKeyboard(

    Display*		 display,
    Time		 time

) {
  puts("XUngrabKeyboard (not implemented)");
}

extern XUngrabServer(

    Display*		 display

) {
  puts("XUngrabServer (not implemented)");
}

extern XUnmapWindow(

    Display*		 display,
    Window		 w

) {
  XDrawable *window = (XDrawable *)w;

  printf("XUnmapWindow: %p", window);

  if (window->data.window.isOpen == False) {
    XEvent *event;

    if ((event = Chox11_CreateMapNotifyEvent(display, window, UnmapNotify))) {
      event->xunmap.window          = w;
      event->xmap.override_redirect = False; /* TODO */
    }

    Window_Hide(window->data.window.handle);
    window->data.window.isOpen = False;
  }
}



extern XUnmapSubwindows(

    Display*		 display,
    Window		 w

) {
  XDrawable *window = (XDrawable *)w;
  int map;

  puts("XUnmapSubWindows");

  for (map = 0; map < window->data.window.nchildren; map++) {
    XUnmapWindow(display, window->data.window.children.ref[map]);
  }
}


extern int XWriteBitmapFile(

    Display*		 display,
    _Xconst char*	 filename,
    Pixmap		 bitmap,
    unsigned int	 width,
    unsigned int	 height,
    int			 x_hot,
    int			 y_hot		     

);


extern char *XLocaleOfIM(

    XIM  /* im*/

);


extern Status XInternalConnectionNumbers(

    Display*			 dpy,
    int**			 fd_return,
    int*			 count_return

);

extern void XProcessInternalConnection(

    Display*			 dpy,
    int				 fd

) {
  puts("XProcessInternalConnection (not implemented)");
}


/**
 * I don't believe these functions have to do anything.
 * The signficance is for sockets.
 */
extern Status XAddConnectionWatch(

    Display*			 dpy,
    XConnectionWatchProc	 callback,
    XPointer			 client_data

) {
  return 1;
}

extern void XRemoveConnectionWatch(

    Display*			 dpy,
    XConnectionWatchProc	 callback,
    XPointer			 client_data

) {
}


extern Atom XInternAtom(

    Display*		 display,
    _Xconst char*	 atom_name,
    Bool		 only_if_exists		 

) {
  XAtom *entry;

  printf("XInternAtom: atom_name='%s', only_if_exists=%i\n",
         atom_name, only_if_exists);

  /* Does the atom already exist? */
  entry = Chox11DB_AtomFind(atom_name);

  /* If not, can we create one? */
  if (entry == NULL) {
    if (only_if_exists == False) {
      entry = Chox11DB_AtomAdd(atom_name);
      if (entry == NULL) return BadAlloc;

      /* Once created, pass back atom ID */
      printf("XInternAtom: returning new atom %x\n", (Atom)entry);
      return (Atom)entry;
    }
    /* Atom doesn't exist */
    else return None;
  }

  /* Fall through, return existing atom ID */
  printf("XInternAtom: returning existing atom %x\n", (Atom)entry);
  return (Atom)entry;
}


extern Status XInternAtoms(

    Display*		 dpy,
    char**		 names,
    int			 count,
    Bool		 onlyIfExists,
    Atom*		 atoms_return

) {
  puts("XInternAtoms (not implemented)");
  *atoms_return = (Atom)calloc(sizeof(Atom), count);
}
