Skip to content
Snippets Groups Projects
Select Git revision
  • aeed4fcf24945879ca06d9a41e2963c9e38300f8
  • master default protected
  • 9.0
  • rxnpatch/rxnpatch
  • 8.0
  • rxnpatch/8.0
  • marcus/wix3
  • nt-tools
  • 7.8
  • 7.6
  • 7.4
  • 7.2
  • 7.0
  • 0.6
  • rosuav/latex-markdown-renderer
  • marcus/gobject-introspection
  • rosuav/pre-listening-ports
  • rosuav/async-annotations
  • rosuav/pgsql-ssl
  • rxnpatch/rxnpatch-broken/2023-10-06T094250
  • grubba/fdlib
  • v8.0.2024
  • v8.0.2022
  • v8.0.2020
  • v8.0.2018
  • v8.0.2016
  • v8.0.2014
  • v8.0.2012
  • v8.0.2008
  • v8.0.2006
  • v8.0.2004
  • v8.0.2002
  • v8.0.2000
  • v8.0.1998
  • v8.0.1996
  • v8.0.1994
  • v8.0.1992
  • v8.0.1990
  • v8.0.1988
  • v8.0.1986
  • rxnpatch/clusters/8.0/2025-04-29T124414
41 results

Xlib.pmod

Blame
  • user avatar
    Per Hedbor authored
    Rev: lib/modules/Protocols.pmod/X.pmod/Atom.pmod:1.5
    Rev: lib/modules/Protocols.pmod/X.pmod/Requests.pmod:1.26
    Rev: lib/modules/Protocols.pmod/X.pmod/Types.pmod:1.32
    Rev: lib/modules/Protocols.pmod/X.pmod/XImage.pmod:1.12
    Rev: lib/modules/Protocols.pmod/X.pmod/Xlib.pmod:1.34
    aeed4fcf
    History
    Xlib.pmod 23.26 KiB
    /* Xlib.pmod
     *
     * $Id: Xlib.pmod,v 1.34 1998/04/21 02:56:05 per Exp $
     */
    
    /*
     *    Protocols.X, a Pike interface to the X Window System
     *
     *    Copyright (C) 1998, Niels Möller, Per Hedbor, Marcus Comstedt,
     *    Pontus Hagland, David Hedbor.
     *
     *    This program is free software; you can redistribute it and/or modify
     *    it under the terms of the GNU General Public License as published by
     *    the Free Software Foundation; either version 2 of the License, or
     *    (at your option) any later version.
     *
     *    This program is distributed in the hope that it will be useful,
     *    but WITHOUT ANY WARRANTY; without even the implied warranty of
     *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     *    GNU General Public License for more details.
     *
     *    You should have received a copy of the GNU General Public License
     *    along with this program; if not, write to the Free Software
     *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
     */
    
    /* Questions, bug fixes and bug reports can be sent to the pike
     * mailing list, pike@idonex.se, or to the athors (see AUTHORS for
     * email addresses. */
    
    #include "error.h"
    
    // #define DEBUG
    
    constant XPORT = 6000;
    
    class rec_buffer
    {
      string buffer;
      int expected;
      int pad;
    
      void create()
      {
        buffer = "";
        expected = pad = 0;
      }
    
      void expect(int e)
      {
        expected = e;
      }
    
      int needs()
      {
        return pad + expected - strlen(buffer);
      }
      
      void add_data(string data)
      {
        buffer += data;
      }
    
      string get_msg()
      {
        if (strlen(buffer) < (expected + pad))
          return 0;
        string res = buffer[pad..pad+expected-1];
        buffer = buffer[pad+expected..];
        pad = (- expected) % 4;
        return res;
      }
    }
    
    class async_request
    {
      object req;
      function callback;
    
      void create(object r, function f)
      {
        req = r;
        callback = f;
      }
    
      void handle_reply(mapping reply)
      {
        callback(1, req->handle_reply(reply));
      }
    
      void handle_error(mapping reply)
      {
        callback(0, req->handle_error(reply));
      }
    }
    
    class id_manager
    {
      int next_id;
      int increment;
      mapping resources;
      
      void create(int base, int mask)
      {
        next_id = base;
        increment = 1;
        while(!(increment & mask))
          increment >>=1;
        resources = ([]);
      }
    
      int alloc_id()
      {
        int id = next_id;
        next_id += increment;
        return id;
      }
    
      mixed lookup_id(int i)
      {
        return resources[i];
      }
    
      void remember_id(int id, mixed resource)
      {
        resources[id] = resource;
      }
    
      void forget_id(int id)
      {
        m_delete(resources, id);
        /* Could make id available for reallocation */
      }
    }
      
    class Display
    {
      import ._Xlib;
      
      inherit Stdio.File;
      inherit id_manager;
      inherit .Atom.atom_manager;
      
    
      
      void close_callback(mixed id);
      void read_callback(mixed id, string data);
    
      // FIXME! Should use some sort of (global) db.
      mapping compose_patterns;
      
      program Struct = ADT.struct;
      
      constant STATE_WAIT_CONNECT = 0;
      constant STATE_WAIT_CONNECT_DATA = 1;
      constant STATE_WAIT_CONNECT_FAILURE = 2;
      constant STATE_WAIT_HEADER = 3;
      constant STATE_WAIT_REPLY = 4;
      constant STATE_CLOSED = 4711;
    
      constant ACTION_CONNECT = 0;
      constant ACTION_CONNECT_FAILED = 1;
      constant ACTION_EVENT = 2;
      constant ACTION_REPLY = 3;
      constant ACTION_ERROR = 4;
      
      int screen_number;
    
      string buffer;
      object received;
      int state;
      int sequence_number;
      
      function io_error_handler;
      function error_handler;
      function close_handler;
      function connect_handler;
      function event_handler;
      function misc_event_handler;
      function reply_handler;
      
      /* Information about the X server */
      int majorVersion, minorVersion;  /* Servers protocol version */
      int release;
      int ridBase, ridMask;
      int motionBufferSize;
      string vendor;
      int maxRequestSize;
      array roots;
      array formats;
      int imageByteOrder, bitmapBitOrder;
      int bitmapScanlineUnit, bitmapScanlinePad;
      int minKeyCode, maxKeyCode;
    
      array key_mapping ;
    
      mapping extensions = ([]); // all available extensions.
    
      mapping pending_requests; /* Pending requests */
      object pending_actions;   /* Actions awaiting handling */
    
    #ifdef DEBUG
      mapping debug_requests = ([ ]);
      #define DEBUGREQ(X) ((X)&0xfff)
    #endif
      
      void create()
      { /* Delay initialization of id_manager */
        compose_patterns = ([]);
        catch {
          compose_patterns = decode_value(Stdio.read_bytes("db/compose.db"));
        };
        atom_manager::create();
      }
      
      void write_callback()
      {
        if (strlen(buffer))
          {
    	int written = write(buffer);
    	if (written < 0)
    	  {
    	    if (io_error_handler)
    	      io_error_handler(this_object());
    	    close();
    	  }
    	else
    	  {
    	    // werror(sprintf("Xlib: wrote '%s'\n", buffer[..written-1]));
    	    buffer = buffer[written..];
    	    // if (!strlen(buffer))
    	    //   set_write_callback(0);
    	  }
          }
      }
    
      void send(string data)
      {
        int ob = strlen(buffer);
        buffer += data;
        if (!ob && strlen(buffer))
          {
    #if 0
    	set_write_callback(write_callback);
    	/* Socket is most likely non-blocking,
    	 * and write_callback() expects to be be able to write
    	 * at least one character. So don't call it yet. */
    #endif
    	write_callback( ); 
          }
      }
    
      /* This function leaves the socket in blocking mode */
      int flush()
      { /* FIXME: Not thread-safe */
        set_blocking();
        int written = write(buffer);
        if (written < strlen(buffer))
          return 0;
        buffer = "";
    
        // werror(sprintf("flush: result = %d\n", result));
        //     trace(0);
        return 1;
      }
      
      void default_error_handler(object me, mapping e)
      {
        if(e->failed_request)
          e->failed_request = e->failed_request[0..32];
        error(sprintf("Xlib: Unhandled error %O\n", e));
      }
    
      void default_event_handler(object me, mapping event)
      {
        int wid;
        object w;
        array a;
        
    //     werror(sprintf("Event: %s\n", event->type));
        if (event->wid && (w = lookup_id(event->wid))
    	&& (a = (w->event_callbacks[event->type])))
          {
    	foreach(a, array pair)
    	  {
    	    if (!(event = pair[1](event, this_object())))
    	      return;
    	  }
    	// FIXME: Should event be forwarded to parent or not?
    	// No, let the widget's signal() function handle that.
          }
        else
          if (misc_event_handler)
    	misc_event_handler(event,this_object());
    //       else
    // 	werror(sprintf("Ignored event %s\n", event->type));
      }
      
      mapping reply;  /* Partially read reply or event */
    
      void get_keyboard_mapping();
    
      array process()
      {
        string msg;
        while (msg = received->get_msg())
          switch(state)
    	{
    	case STATE_WAIT_CONNECT:
    	  {
    	    int success;
    	    int len_reason;
    	    int length;
    	  
    	    sscanf(msg, "%c%c%2c%2c%2c",
    		   success, len_reason,
    		   majorVersion, minorVersion, length);
    	    if (success)
    	      {
    		received->expect(length*4);
    		state = STATE_WAIT_CONNECT_DATA;
    	      } else {
    		received->expect(len_reason);
    		state = STATE_WAIT_CONNECT_FAILURE;
    	      }
    	    break;
    	  }
    	case STATE_WAIT_CONNECT_FAILURE:
    	  return ({ ACTION_CONNECT_FAILED, msg });
    	  close();
    	  state = STATE_CLOSED;
    	  break;
    	case STATE_WAIT_CONNECT_DATA:
    	  {
    	    int nbytesVendor, numRoots, numFormats;
    	    object struct  = Struct(msg);
    
    	    release = struct->get_uint(4);
    	    ridBase = struct->get_uint(4);
    	    ridMask = struct->get_uint(4);
    	    id_manager::create(ridBase, ridMask);
    	    
    	    motionBufferSize = struct->get_uint(4);
    	    nbytesVendor = struct->get_uint(2);
    	    maxRequestSize = struct->get_uint(2);
    	    numRoots = struct->get_uint(1);
    	    numFormats = struct->get_uint(1);
    	    imageByteOrder = struct->get_uint(1);
    	    bitmapBitOrder = struct->get_uint(1);
    	    bitmapScanlineUnit = struct->get_uint(1);
    	    bitmapScanlinePad = struct->get_uint(1);
    	    minKeyCode = struct->get_uint(1);
    	    maxKeyCode = struct->get_uint(1);
    	    /* pad2 */ struct->get_fix_string(4);
    	  
    	    vendor = struct->get_fix_string(nbytesVendor);
    	    /* pad */ struct->get_fix_string( (- nbytesVendor) % 4);
    
    	    int i;
    	    formats = allocate(numFormats);
    	    for(i=0; i<numFormats; i++)
    	      {
    		mapping m = ([]);
    		m->depth = struct->get_uint(1);
    		m->bitsPerPixel = struct->get_uint(1);
    		m->scanLinePad = struct->get_uint(1);
    		/* pad */ struct->get_fix_string(5);
    		formats[i] = m;
    	      }
    
    	    roots = allocate(numRoots);
    	    for(i=0; i<numRoots; i++)
    	      {
    		int wid = struct->get_uint(4);
    		object r = .Types.RootWindow(this_object(), wid);
    		int cm = struct->get_uint(4);
    		r->colormap = r->defaultColorMap = .Types.Colormap(this_object(), cm, 0);
    		r->colormap->autofree=0;
    		r->whitePixel = struct->get_uint(4);
    		r->blackPixel = struct->get_uint(4);
    		r->currentInputMask = struct->get_uint(4);
    		r->pixWidth = struct->get_uint(2);
    		r->pixHeight = struct->get_uint(2);
    		r->mmWidth = struct->get_uint(2);
    		r->mmHeight = struct->get_uint(2);
    		r->minInstalledMaps = struct->get_uint(2);
    		r->maxInstalledMaps = struct->get_uint(2);
    		int rootVisualID = struct->get_uint(4);
    		r->backingStore = struct->get_uint(1);
    		r->saveUnders = struct->get_uint(1);
    		r->rootDepth = struct->get_uint(1);
    		int nDepths = struct->get_uint(1);
    	      
    		r->depths = ([ ]);
    		for (int j=0; j<nDepths; j++)
    		  {
    		    mapping d = ([]);
    		    int depth = struct->get_uint(1);
    		    /* pad */ struct->get_fix_string(1);
    		    int nVisuals = struct->get_uint(2);
    		    /* pad */ struct->get_fix_string(4);
    		  
    		    array visuals = allocate(nVisuals);
    		    for(int k=0; k<nVisuals; k++)
    		      {
    			int visualID = struct->get_uint(4);
    			object v = .Types.Visual(this_object(), visualID);
    
    			v->depth = depth;
    			v->c_class = struct->get_uint(1);
    			v->bitsPerRGB = struct->get_uint(1);
    			v->colorMapEntries = struct->get_uint(2);
    			v->redMask = struct->get_uint(4);
    			v->greenMask = struct->get_uint(4);
    			v->blueMask = struct->get_uint(4);
    			/* pad */ struct->get_fix_string(4);
    			visuals[k] = v;
    		      }
    		    r->depths[depth] = visuals;
    		  }
    		r->visual = lookup_id(rootVisualID);
    		roots[i] = r;
    	      }
    	    if (screen_number >= numRoots)
    	      werror("Xlib.Display->process: screen_number too large.\n");
    	    state = STATE_WAIT_HEADER;
    	    received->expect(32);
    	    get_keyboard_mapping();
    
    	    foreach(values(Extensions), program p)
    	      {
    		object e = p();
    		if(e->init( this_object() ))
    		  extensions[e->name] = e;
    		else
    		  destruct( e ) ;
    	      }
    	    return ({ ACTION_CONNECT });
    	  }
    	case STATE_WAIT_HEADER:
    	  {
    	    received->expect(32); /* Correct for most of the cases */
    	    string type = ._Xlib.event_types[msg[0] & 0x3f];
    	    if (type == "Error")
    	      {
    		mapping m = ([]);
    		int errorCode;
    		sscanf(msg, "%*c%c%2c%4c%2c%c",
    		       errorCode, m->sequenceNumber, m->resourceID,
    		       m->minorCode, m->majorCode);
    		m->errorCode = ._Xlib.error_codes[errorCode];
    #ifdef DEBUG
    		m->failed_request = debug_requests[DEBUGEQ(m->sequenceNumber)];
    #endif
    #if 0
    		if (m->errorCode == "Success")
    		  {
    		    werror("Xlib.Display->process: Error 'Success' ignored.\n");
    		    break;
    		  }
    #endif
    // 		werror(sprintf("Xlib: Received error %O\n", m));
    		return ({ ACTION_ERROR, m });
    	      }
    	    else if (type == "Reply")
    	      {
    		// werror(sprintf("Xlib.Display->process: Reply '%s'\n",
    		// 	       msg));
    		reply = ([]);
    		int length;
    	      
    		sscanf(msg, "%*c%c%2c%4c%s",
    		       reply->data1, reply->sequenceNumber, length,
    		       reply->rest);
    		if (!length)
    		  return ({ ACTION_REPLY, reply });
    
    		state = STATE_WAIT_REPLY;
    		received->expect(length*4);
    	      }
    	    else
    	      {
    		mapping event = ([ "type" : type ]);
    		switch(type)
    		  {
    		  case "KeyPress":
    		  case "KeyRelease":
    		  case "ButtonPress":
    		  case "ButtonRelease":
    		  case "MotionNotify":
    		    {
    		      int root, child;
    		      sscanf(msg, "%*c%c%2c%4c" "%4c%4c%4c"
    			     "%2c%2c%2c%2c" "%2c%c",
    			     event->detail, event->sequenceNumber, event->time,
    			     root, event->wid, child,
    			     event->rootX, event->rootY, event->eventX, 
    			     event->eventY, event->state, event->sameScreen);
    		      event->root = lookup_id(root);
    		      event->event = lookup_id(event->wid);
    		      event->child = child && lookup_id(child);
    		      break;
    		    }
    		  case "EnterNotify":
    		  case "LeaveNotify":
    		    {
    		      int root, child, flags;
    		      sscanf(msg, "%*4c%4c%4c%4c%4c" "%2c%2c%2c%2c" "%2c%c%c",
    			     event->time, root, event->wid, child,
    			     event->rootX, event->rootY, event->eventX, event->eventY,
    			     event->state, event->mode, flags);
    		      event->root = lookup_id(root);
    		      event->event = lookup_id(event->wid);
    		      event->child = child && lookup_id(child);
    		      event->flags = (< >);
    		      if (flags & 1)
    			event->flags->Focus = 1;
    		      if (flags & 2)
    			event->flags->SameScreen = 1;
    		      break;
    		    }
    #if 0
    		  case "FocusIn":
    		  case "FocusOut":
    		    ...;
    #endif
    		  case "KeymapNotify":
    		    event->map = msg[1..];
    		    break;
    		  case "Expose":
    		    {
    		      sscanf(msg, "%*4c%4c" "%2c%2c%2c%2c" "%2c",
    			     event->wid,
    			     event->x, event->y, event->width, event->height,
    			     event->count);
    		      event->window = lookup_id(event->wid);
    		      break;
    		    }
    #if 0		
    		  case "GraphicsExpose":
    		    ...;
    		  case "NoExpose":
    		    ...;
    		  case "VisibilityNotify":
    		    ...;
    #endif
    		  case "CreateNotify":
    		    {
    		      int window;
    		      sscanf(msg, "%*4c%4c%4c" "%2c%2c" "%2c%2c%2c" "%c",
    			     event->wid, window,
    			     event->x, event->y,
    			     event->width, event->height, event->borderWidth,
    			     event->override);
    		      event->parent = lookup_id(event->wid);
    		      event->window = lookup_id(window) || window;
    		      break;
    		    }
    		  case "DestroyNotify":
    		    {
    		      int window;
    		      sscanf(msg, "%*4c%4c%4c",
    			     event->wid, window);
    		      event->window = lookup_id(window) || window;
    		      break;
    		    }
    #if 0
    		  case "UnmapNotify":
    		    ...;
    #endif
    		  case "MapNotify":
    		    {
    		      int window;
    		      sscanf(msg, "%*4c%4c%4c%c",
    			     event->wid, window, event->override);
    		      event->event = lookup_id(event->wid);
    		      event->window = lookup_id(window) || window;
    		      break;
    		    }
    #if 0
    		  case "MapRequest":
    		    ...;
    		  case "ReparentNotify":
    		    ...;
    #endif
    		  case "ConfigureNotify":
    		    {
    		      int window, aboveSibling;
    		      sscanf(msg, "%*4c%4c%4c%4c" "%2c%2c" "%2c%2c%2c" "%c",
    			     event->wid, window, aboveSibling,
    			     event->x, event->y,
    			     event->width, event->height, event->borderWidth,
    			     event->override);
    		      event->window = lookup_id(window) || window;
    		      event->aboveSibling = lookup_id(aboveSibling)
    			|| aboveSibling;
    		      break;
    		    }
    #if 0
    		  case "ConfigureRequest":
    		    ...;
    		  case "GravityNotify":
    		    ...;
    		  case "ResizeRequest":
    		    ...;
    		  case "CirculateNotify":
    		    ...;
    		  case "CirculateRequest":
    		    ...;
    		  case "PropertyNotify":
    		    ...;
    		  case "SelectionClear":
    		    ...;
    		  case "SelectionRequest":
    		    ...;
    		  case "SelectionNotify":
    		    ...;
    		  case "ColormapNotify":
    		    ...;
    		  case "ClientMessage":
    		    ...;
    #endif		
    		  case "MappingNotify":
    		    get_keyboard_mapping();
    		    event = ([ "type" : "MappingNotify",
    				      "raw" : msg ]);
    		    break;
    
    		  default:  /* Any other event */
    // 		    werror("Unimplemented event: "+
    // 			   ._Xlib.event_types[msg[0] & 0x3f]+"\n");
    		    event = ([ "type" :type,
    				      "raw" : msg ]);
    		    break;
    		  }
    		return ({ ACTION_EVENT, event });
    	      }
    	    break; 
    	  }
    	case STATE_WAIT_REPLY:
    	  reply->rest += msg;
    	  state = STATE_WAIT_HEADER;
    	  received->expect(32);
    	  return ({ ACTION_REPLY, reply });
    	}
        return 0;
      }
    
      void handle_action(array a)
      {
        // werror(sprintf("Xlib.Display->handle_action: %O\n", a));
        switch(a[0])
          {
          case ACTION_CONNECT:
    	connect_handler(this_object(), 1);
    	break;
          case ACTION_CONNECT_FAILED:
    	connect_handler(this_object(), 0, a[1]);
    	break;
          case ACTION_EVENT:
    	(event_handler || default_event_handler)(this_object(), a[1]);
    	break;
          case ACTION_REPLY:
    	{
    	  mixed handler = pending_requests[a[1]->sequenceNumber];
    	  if (handler)
    	    {
    	      m_delete(pending_requests, a[1]->sequenceNumber);
    	      handler->handle_reply(a[1]);
    	    }
    	  else if(reply_handler)
    	    reply_handler(this_object(), a[1]);
    	  else
    	    werror("Unhandled reply: "+a[1]->sequenceNumber+"\n");
    	  break;
    	}
          case ACTION_ERROR:
    	{
    	  mixed handler = pending_requests[a[1]->sequenceNumber];
    	  if (handler)
    	    {
    	      m_delete(pending_requests, a[1]->sequenceNumber);
    	      handler->handle_error(a[1]);
    	    }
    	  else
    	    (error_handler || default_error_handler)(this_object(), a[1]);
    	  break;
    	}
          default:
    	error("Xlib.Display->handle_action: internal error\n");
    	break;
          }
      }
      void read_callback(mixed id, string data)
      {
        // werror(sprintf("Xlib: received '%s'\n", data));
        received->add_data(data);
        array a;
        while(a = process())
          handle_action(a);
      }
    
      void close_callback(mixed id)
      {
        if (state == STATE_WAIT_CONNECT)
          connect_handler(this_object(), 0);
        else
          if (close_handler)
    	close_handler(this_object());
          else
    	exit(0);
        close();
      }
      
      void process_pending_actions()
      {
        array a;
        while(a = pending_actions->get())
          handle_action(a);
        set_nonblocking(read_callback, write_callback, close_callback);
      }
    	  
      int open(string|void display)
      {
        int async = !!connect_handler;
        int is_local;
        int display_number;
        
        display = display || getenv("DISPLAY");
        if (!display)
          error("Xlib.pmod: $DISPLAY not set!\n");
    
        array(string) fields = display_re->split(display);
        if (!fields)
          error("Xlib.pmod: Invalid display name!\n");
    
        if (1 != sscanf(fields[1], "%d", display_number))
          error(sprintf("Xlib.Display->open: Invalid display number '%s'.\n",
    		    fields[1]));
    
        string host;
        if (strlen(fields[0]))
          host = fields[0];
        else
          {
    	if(File::open("/tmp/.X11-pipe/X"+((int)display_number), "rw"))
    	  {
    // 	    werror("Using local transport\n");
    	    is_local = 1;
    	  } else {
    // 	    werror("Failed to use local transport.\n");
    	    host = "localhost";
    	  }
          }
        /* Authentication */
    
        mapping auth_data;
        object auth_file = .Auth.read_auth_data();
    
        if (auth_file)
          auth_data = host ? auth_file->lookup_ip(gethostbyname(host)[1][0],
    					      display_number)
    	: auth_file->lookup_local(gethostname(), display_number);
        else
          werror("Xlib: Could not read auth-file\n");
    
        if (!auth_data)
          auth_data = ([ "name" : "", "data" : ""]);
        
        /* Asynchronous connection */
        if (async)
          {
    	if (!is_local)
    	  open_socket();
    	set_nonblocking(0, 0, close_callback);
          }
        if(!is_local)
          {
    	int port =  XPORT + (int)fields[1];
    // 	werror(sprintf("Xlib: Connecting to %s:%d\n", host, port));
    	if (!connect(host, port))
    	{
    //   	  werror(sprintf("Xlib: Connecting to %s:%d failed\n", host, port));
    	  return 0;
     	}
    // 	werror(sprintf("Xlib: Connected to %s:%d\n", host, port));
          }
    
        set_buffer( 65536 );
    
        if(sizeof(fields[2]))
          screen_number = (int) fields[2][1..];
        else
          screen_number = 0;
    
        buffer = "";
        received = rec_buffer();
        pending_requests = ([]);
        pending_actions = ADT.queue();
        sequence_number = 1;
        
        /* Always uses network byteorder (big endian) */
        string msg = sprintf("B\0%2c%2c%2c%2c\0\0%s%s",
    			 11, 0,
    			 strlen(auth_data->name), strlen(auth_data->data),
    			 ._Xlib.pad(auth_data->name), ._Xlib.pad(auth_data->data));
    
        state = STATE_WAIT_CONNECT;
        received->expect(8);
        send(msg);
        if (async)
          {
    	set_nonblocking(read_callback, write_callback, close_callback);
    	return 1;
          }
        if (!flush())
          return 0;
        
        int result = 0;
        int done = 0;
    
        while(1)
          {
    	string data = read(received->needs());
    	if (!data)
    	  return 0;
    	received->add_data(data);
    	array a = process();
    	if (a)
    	  switch(a[0])
    	    {
    	    case ACTION_CONNECT:
    	      get_keyboard_mapping();
    	      set_nonblocking(read_callback, write_callback, close_callback);
    	      return 1;
    	    case ACTION_CONNECT_FAILED:
     	      werror("Connection failed: "+a[1]+"\n");
    	      return 0;
    	      break;
    	    default:
    	      error("Xlib.Display->open: Internal error!\n");
    	    }
          }
      }
    
      int send_request(object req, mixed|void handler)
      {
        string data = req->to_string();
        send(data);
    #ifdef DEBUG
        debug_requests[DEBUGREQ(sequence_number)] = data;
    #endif
        return (sequence_number++)&0xffff; // sequence number is just 2 bytes
      }
    
      array blocking_request(object req)
      {
        int success;
        mixed result = 0;
        int done = 0;
    
        int n = send_request(req);
        flush();
    
        while(!done)
        {
           string data = read(0x7fffffff, 1);
           if (!data)
           {
    	  call_out(close_callback, 0);
    	  return ({ 0, 0 });
           }
           received->add_data(data);
           array a;
           while (a = process())
           {
    	  if ((a[0] == ACTION_REPLY)
    	      && (a[1]->sequenceNumber == n))
    	  {
    	     result = req->handle_reply(a[1]);
    	     done = 1;
    	     success = 1;
    	     break;
    	  }
    	  else if ((a[0] == ACTION_ERROR)
    		   && (a[1]->sequenceNumber == n))
    	  {
    	     result = req->handle_error(a[1]);
    	     done = 1;
    	     break;
    	  }
    	  /* Enqueue all other actions */
    	  pending_actions->put(a);
           }
        }
    
        if (!pending_actions->is_empty())
          call_out(process_pending_actions, 0);
        else
          set_nonblocking(read_callback,write_callback,close_callback);
    
        return ({ success, result });
      }
      
      void send_async_request(object req, function callback)
      {
        int n = send_request(req);
        pending_requests[n] = async_request(req, callback);
      }
    
      void got_mapping(int ok, array foo)
      {
        key_mapping = foo;
      }
    
      void get_keyboard_mapping()
      {
        object r = .Requests.GetKeyboardMapping();
        r->first = minKeyCode;
        r->num = maxKeyCode - minKeyCode + 1;
        send_async_request(r, got_mapping);
      }
    
      object DefaultRootWindow()
      {
        return roots[screen_number];
      }
    
      object OpenFont_req(string name)
      {
        object req = .Requests.OpenFont();
        req->fid = alloc_id();
        req->name = name;
        return req;
      }
    
      mapping (string:object) fonts = ([]);
    
      object OpenFont(string name)
      {
        if(fonts[name]) return fonts[name];
        object req = OpenFont_req(name);
        send_request(req);
        fonts[name] = .Types.Font(this_object(), req->fid);
        return fonts[name];
      }
    
      object CreateGlyphCursor_req(object sourcefont, object maskfont,
    			       int sourcechar, int maskchar,
    			       array(int) foreground, array(int) background)
      {
        object req = .Requests.CreateGlyphCursor();
        req->cid = alloc_id();
        req->sourcefont = sourcefont->id;
        req->maskfont = maskfont->id;
        req->sourcechar = sourcechar;
        req->maskchar = maskchar;
        req->forered = foreground[0];
        req->foregreen = foreground[1];
        req->foreblue = foreground[2];
        req->backred = background[0];
        req->backgreen = background[1];
        req->backblue = background[2];
        return req;
      }
    
      object CreateGlyphCursor(object sourcefont, int sourcechar,
    			   object|void maskfont, int|void maskchar,
    			   array(int)|void foreground,
    			   array(int)|void background)
      {
        if(!maskfont) {
          maskfont = sourcefont;
          if(!maskchar)
    	maskchar = sourcechar + 1;
        }
        object req = CreateGlyphCursor_req(sourcefont, maskfont,
    				       sourcechar, maskchar,
    				       foreground||({0,0,0}),
    				       background||({0xffff,0xffff,0xffff}));
        send_request(req);
        return .Types.Cursor(this_object(), req->cid);
      }
      
      object Bell_req(int volume)
      {
        object req=.Requests.Bell();
        req->percent=volume;
        return req;
      }
      
      void Bell(int volume)
      {
        send_request(Bell_req(volume));
      }
    }