PreviousUpNext

15.4.1661  src/lib/x-kit/xclient/src/window/xserver-ximp.pkg

## xserver-ximp.pkg
#
# For the big picture see the imp dataflow diagrams in
#
#     src/lib/x-kit/xclient/src/window/xclient-ximps.pkg
#
#
#
# Our make_xserver_egg() entrypoint is called (only) from
#
#     make_xclient_ximps_egg()                                  in   src/lib/x-kit/xclient/src/window/xclient-ximps.pkg
#     make_per_screen_xsession_imps() (from open_xsession())    in   src/lib/x-kit/xclient/src/window/xsession-junk.pkg
#
# The first  makes a single master xserver_ximp
# for the socket connection to an X server;
# currently it winds up getting used by atom_ximp               # atom_ximp                                     is from   src/lib/x-kit/xclient/src/iccc/atom-ximp.pkg
# and selection_ximp                                            # selection_ximp                                is from   src/lib/x-kit/xclient/src/window/selection-ximp.pkg
#
# The second makes one xserver_ximp per X "screen".             # The X protocol has different namespaces for different visuals, forcing us to maintain separate xserver-ximps for separate visuals.
# The xserver_ximp from this group for 24-bit RGB depth 
# is the one that will be used for all regular GUI widget
# drawing operations etc.
#
#
#
# For higher-level GUI code (e.g. guiboss_imp) we represent     # guiboss_imp                                   is from   src/lib/x-kit/widget/gui/guiboss-imp.pkg
# the X server: in particular we export a
#     windowsystem_to_xserver::Windowsystem_To_Xserver          # windowsystem_to_xserver                       is from   src/lib/x-kit/xclient/src/window/windowsystem-to-xserver.pkg
# port which supports the
#     draw_ops()
# fn which clients use to actually draw stuff, 
# and also export the
#     x::Op
# type constituting the displaylist for draw_ops().
#
#
#
#
#
# ============================================================
# TO DO:
#
# We could avoid a host of race conditions if imps like encode-xpackets-ximp,
# which essentially wrap an underlying protocol, supported a superset of the
# underlying protocol.  This would reduce the need/temptation to bypass the
# ximp and talk directly to the underlying ximp (xserver-ximp in this case)
# and thus introduce race condition potential.
#
#
# ============================================================
# IMPORTANT IMPLEMENTATION NOTE:
#
# We have only one xsequencer imp per X session, but X semantics
# force us to have multiple xserver ximps per X session
# because different visuals have different namespaces. Also,
# some (naughty!) threads file x requests both directly to
# the xsequencer-imp and also via xerver-imp(s).
#
# Consequently there is considerable risk of race conditions
# between different xrequest delivery paths:  An X request
# issued via one path  may depend on an X request issued via
# another path (say, one which registers an xid for later use);
# if they arrive out of order Bad Things will happen.
#
# Reppy's original eXene system dealt with this by doing
# lots flush() ops -- a highly error-prone approach.
#
# Our approach here is instead to ensure that each call to
# an encode-packets-ximp has deposited any resulting xrequests
# in the xserver-ximp before returning.  The xerver-ximp mailqueue
# then guarantees that all xrequests sent by a given thread, via
# whatever combination of encode-xpacket-ximps and direct calls,
# will reach the X server in the intended (and required) order.
#
# This does mean that all encode-xpackets-ximp calls are blocking
# (synchronous), increasing the potential for deadlock. Probably
# only the find_else_open_font() call can block long enough for
# this to be a significant practical issue...?  Possibly it should
# be treated differently...?
# ============================================================

# Compiled by:
#     src/lib/x-kit/xclient/xclient-internals.sublib


# Compiled by:
#     src/lib/x-kit/xclient/xclient-internals.sublib





stipulate
    include package   threadkit;                                # threadkit                                     is from   src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg
    #
    #
    package un  =  unt;                                         # unt                                           is from   src/lib/std/unt.pkg
    package v1u =  vector_of_one_byte_unts;                     # vector_of_one_byte_unts                       is from   src/lib/std/src/vector-of-one-byte-unts.pkg
    package w2v =  wire_to_value;                               # wire_to_value                                 is from   src/lib/x-kit/xclient/src/wire/wire-to-value.pkg
    package v2w =  value_to_wire;                               # value_to_wire                                 is from   src/lib/x-kit/xclient/src/wire/value-to-wire.pkg
    package e2s =  xerror_to_string;                            # xerror_to_string                              is from   src/lib/x-kit/xclient/src/to-string/xerror-to-string.pkg
    package vu8 =  vector_of_one_byte_unts;                     # vector_of_one_byte_unts                       is from   src/lib/std/src/vector-of-one-byte-unts.pkg
    package g2d =  geometry2d;                                  # geometry2d                                    is from   src/lib/std/2d/geometry2d.pkg
    package xtr =  xlogger;                                     # xlogger                                       is from   src/lib/x-kit/xclient/src/stuff/xlogger.pkg

    package xwp =  windowsystem_to_xevent_router;               # windowsystem_to_xevent_router                 is from   src/lib/x-kit/xclient/src/window/windowsystem-to-xevent-router.pkg
    package pg  =  pen_guts;                                    # pen_guts                                      is from   src/lib/x-kit/xclient/src/window/pen-guts.pkg
    package w2x =  windowsystem_to_xserver;                     # windowsystem_to_xserver                       is from   src/lib/x-kit/xclient/src/window/windowsystem-to-xserver.pkg
    package pc  =  pen_cache;                                   # pen_cache                                     is from   src/lib/x-kit/xclient/src/window/pen-cache.pkg
    package fx  =  font_index;          /* fi is reserved! */   # font_index                                    is from   src/lib/x-kit/xclient/src/window/font-index.pkg
    package x2s =  xclient_to_sequencer;                        # xclient_to_sequencer                          is from   src/lib/x-kit/xclient/src/wire/xclient-to-sequencer.pkg

    package fb  =  font_base;                                   # font_base                                     is from   src/lib/x-kit/xclient/src/window/font-base.pkg
    package dy  =  display;                                     # display                                       is from   src/lib/x-kit/xclient/src/wire/display.pkg
    package pp  =  standard_prettyprinter;                      # standard_prettyprinter                        is from   src/lib/prettyprint/big/src/standard-prettyprinter.pkg

    package xps =  xpacket_sink;                                # xpacket_sink                                  is from   src/lib/x-kit/xclient/src/wire/xpacket-sink.pkg
    package xt  =  xtypes;                                      # xtypes                                        is from   src/lib/x-kit/xclient/src/wire/xtypes.pkg
#   package xet =  xevent_types;                                # xevent_types                                  is from   src/lib/x-kit/xclient/src/wire/xevent-types.pkg
    package wme =  window_map_event_sink;                       # window_map_event_sink                         is from   src/lib/x-kit/xclient/src/window/window-map-event-sink.pkg
    #
    trace =  xtr::log_if  xtr::io_logging  0;                   # Conditionally write strings to tracing.log or whatever.

    nb = log::note_on_stderr;                                   # log                           is from   src/lib/std/src/log.pkg
herein


    # This imp is typically instantiated by:
    #
    #     src/lib/x-kit/xclient/src/window/xclient-ximps.pkg

    package   xserver_ximp
    : (weak)  Xserver_Ximp                                      # Xserver_Ximp                                  is from   src/lib/x-kit/xclient/src/window/xserver-ximp.api
    {
        Xserver_Ximp_State                                                                      # Holds all nonephemeral mutable state maintained by ximp.
            =
            {
              hostwindow_is_mapped:     Ref( Bool ),                                            # When it is not we can and do ignore all draw commands.
              font_index:               fx::Font_Index                                          # Maps fontnames to fb::Font values.
            };

        Imports   = {                                                                           # Ports we use which are exported by other imps.
# XXX SUCKO FIXME we currently never reference   windowsystem_to_xevent_router
# -- we should drop it if we don't find a use for it soon.
                      windowsystem_to_xevent_router:    xwp::Windowsystem_To_Xevent_Router,     # Directs X mouseclicks etc to right hostwindow.
                      xclient_to_sequencer:             x2s::Xclient_To_Sequencer               # All drawing commands go to sequencer, outbuf then Xserver.
                    };

        Me_Slot = Mailslot( {  imports: Imports,
                                   me:          Xserver_Ximp_State,
                                   run_gun':    Run_Gun,
                                   end_gun':    End_Gun,
                                   xdisplay:    dy::Xdisplay,
                                   drawable:    xt::Drawable_Id                                 # Drawable from display
                                 }
                              );

        Exports   = {                                                                           # Ports we export for use by other imps.
# XXX SUCKO FIXME I can find no evidence that this is ever called.
# It expects to be called with one of the three values
#                           fun do_map_plea wme::s::HOSTWINDOW_IS_NOW_UNMAPPED  =>      me.hostwindow_is_mapped := FALSE;
#                               do_map_plea wme::s::HOSTWINDOW_IS_NOW_MAPPED    =>      me.hostwindow_is_mapped := TRUE;
#                               do_map_plea wme::s::FIRST_EXPOSE                =>      me.hostwindow_is_mapped := TRUE;
#                           end;
# Looks like this should maybe be done by 
src/lib/x-kit/xclient/src/window/xevent-to-widget-ximp.pkg
# in response to
#     xet::x::UNMAP_NOTIFY
#     xet::x::MAP_NOTIFY
#     xet::x::EXPOSE
#
                      window_map_event_sink:    wme::Window_Map_Event_Sink,                     # Tells us when our window is un/mapped (hidden/revealed).
                      windowsystem_to_xserver:  w2x::Windowsystem_To_Xserver                    # Draw commands (etc) from widget/application code.
                    };



        Option = MICROTHREAD_NAME String;                                                       # 

        Xserver_Egg =  Void -> (Exports,   (Imports, Run_Gun, End_Gun) -> Void);

        Map_Q    =  Mailqueue( wme::s::Mapped_State     );

        Runstate =  {                                                                           # These values will be statically globally visible throughout the code body for the imp.
                      me:                               Xserver_Ximp_State,                     # 
                      imports:                          Imports,                                # Ximps to which we send requests.
                      to:                               Replyqueue,                             # The name makes   foo::pass_something(imp) to {. ... }   syntax read well.
                      end_gun':                         End_Gun,                                # We shut down the microthread when this fires.
                      map_q:                            Map_Q,                                  # Notifications that our hostwindow has been un/mappsed.
                      xdisplay:                         dy::Xdisplay,
                      next_xid:                         Void -> xt::Xid,
                      pen_cache:                        pc::Pen_Cache
                    };


        Client_Q =  Mailqueue( Runstate -> Void         );



        # Officially Mythryl does not have pointer equality,                                    # NB: garbage collection moving stuff around in memory will not corrupt this comparison
        # but we do it here anyway for speed.  Naughty! :-)                                     # because they happen only at the start of a fn and unsafe::cast isn't a fn, just an inline primitive.
        #
        fun pen_eq
            ( a:  pg::Pen,
              b:  pg::Pen
            )
            =
            {   ((unsafe::cast a): Int)
                ==
                ((unsafe::cast b): Int);
            };

        # Bitmasks for the various components of a pen.                                         # CAVEAT PROGRAMMER!  The bit-numbering here is must match that of
        #                                                                                       #                     extract_mask()    in   src/lib/x-kit/xclient/src/window/pen.pkg
        pen_function            = (0u1 << 0u0); 
        pen_plane_mask          = (0u1 << 0u1);
        #
        pen_foreground          = (0u1 << 0u2);
        pen_background          = (0u1 << 0u3);
        #
        pen_line_width          = (0u1 << 0u4);
        pen_line_style          = (0u1 << 0u5);
        #
        pen_cap_style           = (0u1 << 0u6);
        pen_join_style          = (0u1 << 0u7);
        #
        pen_fill_style          = (0u1 << 0u8);
        pen_fill_rule           = (0u1 << 0u9); 
        #
        pen_tile                = (0u1 << 0u10);
        pen_stipple             = (0u1 << 0u11);
        #
        pen_tile_stip_origin    = (0u1 << 0u12);
        pen_subwindow_mode      = (0u1 << 0u13);
        #
        pen_clip_origin         = (0u1 << 0u14);
        pen_clip_mask           = (0u1 << 0u15);
        #
        pen_dash_offset         = (0u1 << 0u16);
        pen_dash_list           = (0u1 << 0u17);
        #
        pen_arc_mode            = (0u1 << 0u18);
        pen_exposures           = 0u0;                                                                                  #  (0u1 << 0u19) 

        stipulate
            standard_pen_components                                                                                     # The standard pen components used by most ops.
                #
                = pen_function
                | pen_plane_mask
                | pen_subwindow_mode
                | pen_clip_origin
                | pen_clip_mask
                | pen_foreground
                | pen_background
                | pen_tile
                | pen_stipple
                | pen_tile_stip_origin
                ;

            standard_linedrawing_pen_components                                                                         # The pen components used by line-drawing operations.
                #
                =  standard_pen_components
                | pen_line_width
                | pen_line_style
                | pen_cap_style
                | pen_join_style
                | pen_fill_style
                | pen_dash_offset
                | pen_dash_list
                ;
        herein
            #
            fun pen_vals_used (w2x::x::POLY_POINT    _) =>  standard_pen_components;
                pen_vals_used (w2x::x::COPY_PMAREA   _) =>  standard_pen_components;
                pen_vals_used (w2x::x::COPY_PMPLANE  _) =>  standard_pen_components;
                pen_vals_used (w2x::x::PUT_IMAGE     _) =>  standard_pen_components;
                pen_vals_used (w2x::x::IMAGE_TEXT8   _) =>  standard_pen_components;
                #
                pen_vals_used (w2x::x::POLY_TEXT8    _) => (standard_pen_components | pen_fill_style);
                pen_vals_used (w2x::x::POLY_TEXT16   _) => (standard_pen_components | pen_fill_style);
                pen_vals_used (w2x::x::FILL_POLY     _) => (standard_pen_components | pen_fill_style);
                pen_vals_used (w2x::x::POLY_FILL_BOX _) => (standard_pen_components | pen_fill_style);
                pen_vals_used (w2x::x::POLY_FILL_ARC _) => (standard_pen_components | pen_fill_style);
                #
                pen_vals_used (w2x::x::COPY_AREA     _) =>  standard_pen_components | pen_exposures;
                pen_vals_used (w2x::x::COPY_PLANE    _) =>  standard_pen_components | pen_exposures;
                #
                pen_vals_used (w2x::x::POLY_LINE     _) =>  standard_linedrawing_pen_components;
                pen_vals_used (w2x::x::POLY_SEG      _) =>  standard_linedrawing_pen_components;
                pen_vals_used (w2x::x::POLY_BOX      _) =>  standard_linedrawing_pen_components;
                pen_vals_used (w2x::x::POLY_ARC      _) =>  standard_linedrawing_pen_components;
                #
                pen_vals_used (w2x::x::CLEAR_AREA    _) =>  0u0;
            end;
        end;
        #
        fun run ( client_q:                             Client_Q,                                                       # Requests from x-widgets and such via draw_imp, pen_imp or draw_imp.
                  xrequests_ready_to_send:              Ref(List( v1u::Vector )),
                  #
                  runstate as   
                  {                                                                                                     # These values will be statically globally visible throughout the code body for the imp.
                    me:                                 Xserver_Ximp_State,                                             # 
                    imports:                            Imports,                                                        # Ximps to which we send requests.
                    to:                                 Replyqueue,                                                     # The name makes   foo::pass_something(imp) to {. ... }   syntax read well.
                    end_gun':                           End_Gun,                                                        # We shut down the microthread when this fires.
                    map_q:                              Map_Q,                                                          # Notifications that our hostwindow has been un/mappsed.
                    xdisplay:                           dy::Xdisplay,
                    next_xid:                           Void -> xt::Xid,
                    pen_cache:                          pc::Pen_Cache
                  }
                )
            =
            outer_loop ()
            where
                sp = imports.xclient_to_sequencer;

                #
                fun note_xrequest  xrequest                                                                             # 
                    =
                    xrequests_ready_to_send :=  xrequest ! *xrequests_ready_to_send;                                    # Notice most recent xrequest is at front, so we'll need to reverse list before sending it.
 
                fun send_pending_xrequests ()
                    =
                    if (*xrequests_ready_to_send != NIL)
                        #
                        sp.send_xrequests (reverse *xrequests_ready_to_send);                                           # Send all x-requests generated by this loop, reversing to restore correct order.
                        xrequests_ready_to_send := [];                                                                  # 
                    fi;
 
                #
                fun outer_loop ()                                                                                       # Outer loop for the imp.
                    =
                    {   do_one_mailop' to [
                            #
                            (end_gun'                       ==>  shut_down_draw_imp'),
                            (take_from_mailqueue' client_q  ==>  do_client_plea),
                            (take_from_mailqueue' map_q     ==>  do_map_plea)
                        ];
 
                        outer_loop ();
                    }   
                    where
                        fun do_client_plea thunk
                            =
                            thunk runstate;
 
 
                        fun shut_down_draw_imp' ()
                            =
                            thread_exit { success => TRUE };                                                            # Will not return.      
                        #
 
                            fun do_map_plea wme::s::HOSTWINDOW_IS_NOW_UNMAPPED  =>      me.hostwindow_is_mapped := FALSE;
                                do_map_plea wme::s::HOSTWINDOW_IS_NOW_MAPPED    =>      me.hostwindow_is_mapped := TRUE;
                                do_map_plea wme::s::FIRST_EXPOSE                =>      me.hostwindow_is_mapped := TRUE;
                            end;
                            #
                    end;                                                                                                # fun outer_loop
            end;                                                                                                        # fun run
        
draw_ops_calls = REF 0;
        fun startup   (reply_oneshot:  Oneshot_Maildrop( (Me_Slot, Exports) ))   ()                                     # Root fn of imp microthread.  Note currying.
            =
            {   me_slot     =  make_mailslot  ()        :  Me_Slot;
                #
                windowsystem_to_xserver
                          =
                          { 
                    xclient_to_sequencer                                                                        # Xsequencer-forwarding calls.  The point of including this facility
                                  =>                                                                                    # is that clients can avoid race conditions by always talking to us;
                                  { send_xrequest,                                                                      # if they talk both to us and directly to the xsequencer subtle
                                    send_xrequests,                                                                     # race conditions may arise in which behavior is non-deterministic,
                                    send_xrequest_and_read_reply,                                                       # depending on whether we or the xsequencer run next.
                                    send_xrequest_and_read_reply',
                                    send_xrequest_and_pass_reply,
                                    send_xrequest_and_return_completion_mailop,
                                    send_xrequest_and_return_completion_mailop'
                                  },
                            draw_ops,
                            destroy_window,
                            destroy_pixmap,
                            find_else_open_font
                          };


                window_map_event_sink =  { put_value };

                to =  make_replyqueue();

                put_in_oneshot (reply_oneshot, (me_slot, { windowsystem_to_xserver, window_map_event_sink }));          # Return value from xserver_egg'().

                (take_from_mailslot  me_slot)                                                                           # Imports from xserver_egg'().
                    ->
                    { me, imports, run_gun', end_gun', xdisplay, drawable };

                xdisplay -> { next_xid, ... }: dy::Xdisplay;

                block_until_mailop_fires  run_gun';                                                                     # Wait for the starting gun.

                graphics_expose_event_accumulator = REF NULL;

                pen_cache =  pc::make_pen_cache { drawable, next_xid, note_xrequest };

                if (*xrequests_ready_to_send != NIL)
                    #
                    imports.xclient_to_sequencer.send_xrequests  (reverse *xrequests_ready_to_send);
                fi;

                run (client_q, xrequests_ready_to_send, { me, map_q, imports, to, end_gun', xdisplay, next_xid, pen_cache });                   # Will not return.
            }
            where
                client_q  =  make_mailqueue (get_current_microthread()) :  Client_Q;
                map_q     =  make_mailqueue (get_current_microthread()) :  Map_Q;

                xrequests_ready_to_send =  REF ([]:  List( v1u::Vector ));                                              # This holds all xrequests for xsequencer_ximp for one loop.
                                                                                                                        #     The point of this is that batched xrequests can be handled more efficiently;
                                                                                                                        # in particular they can be combined into (near) max-size ethernet packets instead of being
                                                                                                                        # sent as a sequence of near-min-size ethernet packets with much more overhead per xrequest
                                                                                                                        # both in terms of packet-header bytes overhead and also in terms of CPU cycles needed to
                                                                                                                        # process that overhead.
                                                                                                                        #     Reppy did xrequest batching by having outbuf hold xrequests for several milliseconds or
                                                                                                                        # until a reasonable number were accomplished, but this introduced undesirable GUI response
                                                                                                                        # latency which he was then forced to work around via special hacks to disable these waits.
                                                                                                                        # Application programmers who neglected to invoke this special magic would get poor GUI response.
                                                                                                                        #     A core concern of GUI design and implementation is absolutely minimizing latency, so I
                                                                                                                        # prefer to NEVER introduce any artificial added latency, instead achieving xrequest batching
                                                                                                                        # by having upstream code submit lists of xrequests in place of single xrequests.  (My design
                                                                                                                        # is based on explicit GUI display lists well-suited to request batching, where Reppy's design
                                                                                                                        # was focussed on having application code make individual draw calls -- "immediate mode".)
                                                                                                                        #     Reppy used mailslots for inter-imp mail but I'm using mailqueues, to reduce deadlock risk.
                                                                                                                        # This allows outbuf to use   take_all_from_mailqueue'  to read an entire queueful of input when
                                                                                                                        # it wakes, potentially combining multiple xrequestlists into a single xrequestlist.
                                                                                                                        #     Doing so many assignments to 'xrequests_ready_to_send' does involve some added heapcleaner
                                                                                                                        # overhead, so as a performance-tuning tweak we MIGHT want to pass the xrequest list up and down
                                                                                                                        # every call chain using it.  This would however clutter the code and increase potential for bugs,
                                                                                                                        # so I'm not doing in this first-cut version of the code.
                                                                                                                        #                                                              -- 2013-07-19 CrT


                fun note_xrequest  xrequest                                                                             # 
                    =
                    xrequests_ready_to_send :=  xrequest ! *xrequests_ready_to_send;                                    # Notice most recent xrequest is at front, so we'll need to reverse list before sending it.

                fun send_pending_xrequests (imports: Imports)
                    =
                    if (*xrequests_ready_to_send != NIL)
                        #
                        imports.xclient_to_sequencer.send_xrequests (reverse *xrequests_ready_to_send);                 # Send all x-requests generated by this loop, reversing to restore correct order.
                        xrequests_ready_to_send := [];                                                                  # 
                    fi;

                #
                fun encode_drawops_as_xrequests { ops, gc_id, font_id }                                                 # Convert a list of draw ops to bytevector wire encoding for eventual transmission to X-server.
                    =
                    apply encode ops
                    where
                        fun encode  { to, op => w2x::x::POLY_LINE (relative, points)            }       =>      note_xrequest (v2w::encode_poly_line     { drawable=>to, gc_id, items=>points, relative         });
                            encode  { to, op => w2x::x::POLY_SEG lines                          }       =>      note_xrequest (v2w::encode_poly_segment  { drawable=>to, gc_id, items=>lines                    });
                            encode  { to, op => w2x::x::FILL_POLY (shape, relative, points)     }       =>      note_xrequest (v2w::encode_fill_poly     { drawable=>to, gc_id, points, relative, shape         });
                            encode  { to, op => w2x::x::POLY_BOX boxes                          }       =>      note_xrequest (v2w::encode_poly_box      { drawable=>to, gc_id, items=>boxes                    });
                            encode  { to, op => w2x::x::POLY_FILL_BOX boxes                     }       =>      note_xrequest (v2w::encode_poly_fill_box { drawable=>to, gc_id, items=>boxes                    });
                            encode  { to, op => w2x::x::POLY_ARC arcs                           }       =>      note_xrequest (v2w::encode_poly_arc      { drawable=>to, gc_id, items=>arcs                     });
                            encode  { to, op => w2x::x::POLY_FILL_ARC arcs                      }       =>      note_xrequest (v2w::encode_poly_fill_arc { drawable=>to, gc_id, items=>arcs                     });
                            encode  { to, op => w2x::x::CLEAR_AREA box                          }       =>      note_xrequest (v2w::encode_clear_area    { window_id=>to, box, exposures => FALSE               });

                            encode  { to, op => w2x::x::POLY_POINT (relative, points)   }
                                =>
#                                           note_xrequest  (v2w::encode_poly_point { drawable=>to, gc_id, items=>points, relative });           # Replaced by below code.
                                {
                                    # "Discovered there's a limit to the number
                                    #  of points that can be sent to the X server.
                                    #  It's less than 65535, but at least 65400.
                                    #  I figure this is close enough:"              -- Hue White 2011-11-24
                                    #
                                    x_limit = 65400;
                                    #
                                    # Maybe this should be handled in v2w rather than here?
                                    # Probably similar limits apply to all the other cases here.
                                    # XXX BUGGO FIXME -- 2013-07-12 CrT         # This should probably be derived from XDISPLAY.max_request_length - <request size>     -- CrT 2014-02-01  XXX BUGGO FIXME

                                    encode_points  points
                                    where
                                        fun encode_points [] => ();
                                            #   
                                            encode_points points
                                                =>
                                                if (list::length(points) <= x_limit)    note_xrequest (v2w::encode_poly_point { drawable=>to, gc_id, relative, items=> points                           });
                                                else                                note_xrequest (v2w::encode_poly_point { drawable=>to, gc_id, relative, items=> list::take_n (points, x_limit)       });
                                                                                        encode_points (list::drop_n (points, x_limit));
                                                fi;
                                        end;
                                    end;
                                };


                            encode  { to, op => w2x::x::COPY_PMAREA (pt, from, box)     }
                                =>
                                {   (g2d::box::upperleft_and_size  box)
                                        ->
                                        (p, size);

                                    note_xrequest (v2w::encode_copy_area { gc_id, from, to, from_point=>p, size, to_point=>pt });
                                };

                            encode  { to, op => w2x::x::COPY_PMPLANE (pt, from, box, plane)     }
                                =>
                                {   (g2d::box::upperleft_and_size  box)
                                        ->
                                        (p, size);

                                    note_xrequest (v2w::encode_copy_plane { gc_id, from, to, from_point=>p, size, to_point=>pt, plane });
                                };


                            encode  { to, op => w2x::x::PUT_IMAGE ims }
                                =>
                                apply do_im ims
                                where
                                    fun do_im (im:  w2x::x::Image)
                                        =
                                        note_xrequest (
                                            #
                                            v2w::encode_put_image
                                              {
                                                drawable => to,
                                                gc_id,
                                                depth  => im.depth,
                                                to     => im.to_point,
                                                size   => im.size,
                                                lpad   => im.lpad,
                                                format => im.format,
                                                data   => im.data
                                              }
                                        );
                                end;


                            encode { to, op => w2x::x::COPY_AREA (pt, from, box)                }
                                =>
                                {   (g2d::box::upperleft_and_size  box)
                                        ->
                                        (p, size);

                                    note_xrequest (v2w::encode_copy_area { gc_id, from, to, from_point=>p, size, to_point=>pt });
                                };

                            encode { to, op => w2x::x::COPY_PLANE (pt, from, box, plane)        }
                                =>
                                {   (g2d::box::upperleft_and_size  box)
                                        ->
                                        (p, size);

                                    note_xrequest (v2w::encode_copy_plane { gc_id, from, to, from_point=>p, size, to_point=>pt, plane });
                                };

                            encode { to, op => w2x::x::IMAGE_TEXT8 (_, point, string)   }
                                =>
                                note_xrequest (v2w::encode_image_text8 { drawable=>to, gc_id, point, string });

                            encode { to, op => w2x::x::POLY_TEXT8 (fid, point, txt_items)       }
                                =>
                                note_xrequest   (   v2w::encode_poly_text8
                                                    {
                                                      drawable=>to,
                                                      gc_id,
                                                      point,
                                                      items =>  do_items txt_items
                                                    }
                                                )
                                where
                                    last_fid =  f (fid, txt_items)
                                                where
                                                    fun f (last_fid, [])                    =>  last_fid;
                                                        f (last_fid, (w2x::t::FONT id) ! r) =>  f (id, r);
                                                        f (last_fid, _ ! r)                 =>  f (last_fid, r);
                                                    end;
                                                end;

                                    txt_items = last_fid == font_id
                                                ?? txt_items
                                                :: txt_items @ [w2x::t::FONT font_id];

                                    txt_items = fid == font_id
                                                ?? txt_items
                                                :: (w2x::t::FONT fid) ! txt_items;

                                    #
                                    fun split_delta (0, l)
                                            =>
                                            l;

                                        split_delta (i, l)
                                            =>
                                            if (i < -128)
                                                #
                                                split_delta (i+128, -128 ! l);
                                            else
                                                i > 127
                                                ?? split_delta (i - 127, 127 ! l)
                                                :: i ! l;
                                            fi;
                                    end;


                                    # Split a string into legal
                                    # lengths for a PolyText8 command 
                                    #
                                    fun split_text ""
                                            =>
                                            [];

                                        split_text s
                                            =>
                                            {   n = string::length_in_bytes s;
                                                #
                                                fun split (i, l)
                                                    =
                                                    n - i  > 254
                                                    ??  split (i+254,  substring (s, i, 254) ! l)
                                                    ::  list::reverse (substring (s, i, n-i) ! l);

                                                n > 254  ??  split (0, [])
                                                         ::  [s];
                                            };
                                    end;

                                    #
                                    fun split_item (w2x::t::FONT id)
                                            =>
                                            [xt::FONT_ITEM id];

                                        split_item (w2x::t::TEXT (delta, s))
                                            =>
                                            case (split_delta (delta, []), split_text s)
                                                #
                                                ([], []) =>   [];
                                                ([], sl) =>   (map (\\ s = xt::TEXT_ITEM (0,  s)) sl);
                                                (dl, []) =>   (map (\\ n = xt::TEXT_ITEM (n, "")) dl);

                                                ([d], s ! sr)
                                                    =>
                                                    (xt::TEXT_ITEM (d, s) ! (map (\\ s = xt::TEXT_ITEM (0, s)) sr));

                                                (d ! dr, s ! sr)
                                                    =>
                                                    (                        map (\\ n = xt::TEXT_ITEM (n,"")) dr)
                                                    @
                                                    (xt::TEXT_ITEM (d, s) ! (map (\\ s = xt::TEXT_ITEM (0, s)) sr));
                                            esac;

                                    end;

                                    do_items   =    fold_backward
                                                        (\\ (item, l) =  (split_item item) @ l)
                                                        [];
                                end;

                            encode { to, op => w2x::x::POLY_TEXT16 (fid, point, txt_items)      }                       # Mostly identical to above POLY_TEXT8 case.
                                =>
                                note_xrequest   (   v2w::encode_poly_text16
                                                    {
                                                      drawable=>to,
                                                      gc_id,
                                                      point,
                                                      items =>  do_items txt_items
                                                    }
                                                )
                                where
                                    last_fid =  f (fid, txt_items)
                                                where
                                                    fun f (last_fid, [])                    =>  last_fid;
                                                        f (last_fid, (w2x::t::FONT id) ! r) =>  f (id, r);
                                                        f (last_fid, _ ! r)                 =>  f (last_fid, r);
                                                    end;
                                                end;

                                    txt_items = last_fid == font_id
                                                ?? txt_items
                                                :: txt_items @ [w2x::t::FONT font_id];

                                    txt_items = fid == font_id
                                                ?? txt_items
                                                :: (w2x::t::FONT fid) ! txt_items;

                                    #
                                    fun split_delta (0, l)
                                            =>
                                            l;

                                        split_delta (i, l)
                                            =>
                                            if (i < -128)
                                                #
                                                split_delta (i+128, -128 ! l);
                                            else
                                                i > 127
                                                ?? split_delta (i - 127, 127 ! l)
                                                :: i ! l;
                                            fi;
                                    end;


                                    # Split a string into legal
                                    # lengths for a PolyText16 command 
                                    #
                                    fun split_text ""
                                            =>
                                            [];

                                        split_text s
                                            =>
                                            {   n = string::length_in_bytes s;
                                                #
                                                fun split (i, l)
                                                    =
                                                    n - i  > 254
                                                    ??  split (i+254,  substring (s, i, 254) ! l)
                                                    ::  list::reverse (substring (s, i, n-i) ! l);

                                                n > 254  ??  split (0, [])
                                                         ::  [s];
                                            };
                                    end;

                                    #
                                    fun split_item (w2x::t::FONT id)
                                            =>
                                            [xt::FONT_ITEM id];

                                        split_item (w2x::t::TEXT (delta, s))
                                            =>
                                            case (split_delta (delta, []), split_text s)
                                                #
                                                ([], []) =>   [];
                                                ([], sl) =>   (map (\\ s = xt::TEXT_ITEM (0,  s)) sl);
                                                (dl, []) =>   (map (\\ n = xt::TEXT_ITEM (n, "")) dl);

                                                ([d], s ! sr)
                                                    =>
                                                    (xt::TEXT_ITEM (d, s) ! (map (\\ s = xt::TEXT_ITEM (0, s)) sr));

                                                (d ! dr, s ! sr)
                                                    =>
                                                    (                        map (\\ n = xt::TEXT_ITEM (n,"")) dr)
                                                    @
                                                    (xt::TEXT_ITEM (d, s) ! (map (\\ s = xt::TEXT_ITEM (0, s)) sr));
                                            esac;

                                    end;

                                    do_items   =    fold_backward
                                                        (\\ (item, l) =  (split_item item) @ l)
                                                        [];
                                end;
                        end;
                    end;




                ###################################################################################
                # window_map_event_sink
                #
                fun put_value (state:  wme::s::Mapped_State)
                    =
                    {
                        put_in_mailqueue (map_q, state);
                    };


                ###################################################################################
                # xsequencer
                #
                stipulate
                    fun unwrap_reply  x2s::REPLY_LOST     =>  { log::fatal   "xsequencer-ximp.pkg: Lost X-server reply";                                                        raise exception DIE "LOST REPLY";  };
                        unwrap_reply (x2s::REPLY_ERROR s) =>  { log::fatal ( "xsequencer-ximp.pkg: X-server error: " + (e2s::xerror_to_string (w2v::decode_error s)));  raise exception DIE "ERROR_REPLY"; };
                        unwrap_reply (x2s::REPLY s)       =>  s;                                                                                                                # NB log::fatal should never return;
                    end;                                                                                                                                                # above 'raises' keep typechecker happy.
                    fun unwrap_flag r
                            =
                            {   unwrap_reply r;
                                ();
                            };
                herein
                    fun send_xrequest   (xrequest:  v1u::Vector)
                        =
                        put_in_mailqueue  (client_q,
                            #
                            \\ ({ me, imports, ... }: Runstate)
                                =
                                imports.xclient_to_sequencer.send_xrequest  xrequest
# p::SEND_XREQUEST vec
                        );


                    fun send_xrequests  (xrequests: List( v1u::Vector ))
                        =
                        put_in_mailqueue  (client_q,
                            #
                            \\ ({ me, imports, ... }: Runstate)
                                =
                                imports.xclient_to_sequencer.send_xrequests  xrequests
# p::SEND_XREQUESTS vecs
                        );


                    fun send_xrequest_and_read_reply (xrequest: v1u::Vector)
                        =
                        {   reply_oneshot =  make_oneshot_maildrop():  Oneshot_Maildrop( x2s::Reply_Mail );
                            #
                            put_in_mailqueue  (client_q,
                            #
                            \\ ({ me, imports, ... }: Runstate)
                                =
                                imports.xclient_to_sequencer.send_xrequest_and_read_reply'  (xrequest, reply_oneshot)

#  p::SEND_XREQUEST_AND_READ_REPLY (xrequest, reply_oneshot)
                            );

                            get_from_oneshot'  reply_oneshot
                                ==>
                                unwrap_reply;
                        };                                                                                                      # This is why we wait on the result oneshot even though there is no return value.

                    fun send_xrequest_and_read_reply'  (xrequest: v1u::Vector,   reply_oneshot: Oneshot_Maildrop(x2s::Reply_Mail))
                        =
                        put_in_mailqueue  (client_q,
                            #
                            \\ ({ me, imports, ... }: Runstate)
                                =
                                imports.xclient_to_sequencer.send_xrequest_and_read_reply'  (xrequest, reply_oneshot)

#  p::SEND_XREQUEST_AND_READ_REPLY (xrequest, reply_oneshot)
                        );

                    fun send_xrequest_and_pass_reply
                            (xrequest:          v1u::Vector)
                            (replyqueue:        Replyqueue)
                            (reply_handler:     v1u::Vector -> Void)
                        =
                        put_in_mailqueue  (client_q,
                            #
                            \\ ({ me, imports, ... }: Runstate)
                                =
                                imports.xclient_to_sequencer.send_xrequest_and_pass_reply  xrequest  replyqueue  reply_handler

#  p::SEND_XREQUEST_AND_PASS_REPLY (xrequest, replyqueue, reply_handler)
                        );

                    fun send_xrequest_and_return_completion_mailop  (xrequest: v1u::Vector)
                        =
                        {   reply_oneshot2 =  make_oneshot_maildrop ():  Oneshot_Maildrop(x2s::Reply_Mail);
                            #
                            put_in_mailqueue  (client_q,
                                #
                                \\ ({ me, imports, ... }: Runstate)
                                    =
                                    imports.xclient_to_sequencer.send_xrequest_and_return_completion_mailop'  (xrequest, reply_oneshot2)

#  p::SEND_XREQUEST_AND_RETURN_COMPLETION_MAILOP (xrequest, reply_oneshot2)
                            );

                            # Construct and return a mailop which caller can
                            #     block_until_mailop_fires
                            # on to await completion of the requested operation:
                            #
                            get_from_oneshot' reply_oneshot2
                                ==>
                                unwrap_flag;
                        };

                    fun send_xrequest_and_return_completion_mailop'  (arg as   (xrequest: v1u::Vector,   reply_oneshot2: Oneshot_Maildrop(x2s::Reply_Mail)))
                        =
                        put_in_mailqueue  (client_q,
                            #
                            \\ ({ me, imports, ... }: Runstate)
                                =
                                imports.xclient_to_sequencer.send_xrequest_and_return_completion_mailop'  (xrequest, reply_oneshot2)
#  p::SEND_XREQUEST_AND_RETURN_COMPLETION_MAILOP arg
                        );

                end;

                ###################################################################################
                # xserver
                #
                fun draw_ops    (drawoplist:  List( w2x::Draw_Op ))
                    =
                    {
                        reply_1shot =  make_oneshot_maildrop():  Oneshot_Maildrop( Void );
                        #
                        put_in_mailqueue  (client_q,
                            #
                            \\ ({ me, imports, pen_cache, ... }: Runstate)
                                =
#  p::DRAW_OPS (draw_ops, reply_oneshot)
#                           # Send a list of drawing commands out to the sequencer.
#                           # This involves:
#                           #
#                           #  o  Breaking the list up into sublists which can
#                           #     share a common graphics context.
#                           #
#                           #  o  Acquiring the required X-server graphics contexts
#                           #     for the operations from pen_cache
#                           #
#                           #  o  Encoding each command as a bytevector for
#                           #     network transmission.
#                           #
#                           fun do_drawoplist  (drawoplist:  List( w2x::Draw_Op ), reply_1shot: Oneshot_Maildrop(Void))
#                               =
(                               {   drawoplists =  break_drawoplist_into_mono_gc_drawoplists  (drawoplist, []);
                                    #
                                    apply  encode_and_send_mono_gc_drawoplist  drawoplists;

                                    send_pending_xrequests imports;             # Per top-of-file comments, it is critically important we complete send_pending_xrequests before doing our terminal put_in_oneshot() call.

                                    put_in_oneshot (reply_1shot, ());
                                }
                                where 

                                    Gc_Info
                                      = NO_GC
                                      | NO_FONT
                                      | WITH_FONT xt::Font_Id
                                      | SET_FONT  xt::Font_Id
                                      ;

                                    allot_gc                =   pc::allocate_graphics_context                   pen_cache;
                                    allot_gc_with_font      =   pc::allocate_graphics_context_with_font         pen_cache;
                                    allot_gc_and_set_font   =   pc::allocate_graphics_context_and_set_font      pen_cache;
                                    #
                                    free_gc                 =   pc::free_graphics_context                       pen_cache;
                                    free_gc_and_font        =   pc::free_graphics_context_and_font              pen_cache;



                                    # We are given a list of X draw-ops List(w2x::x::Op)
                                    # to be performed.  For efficiency, we want to avoid
                                    # switching graphics contexts needlessly, so we break our
                                    # argument draw-op list into a sequence of sublists,
                                    # each of which can be performed using a single gc.
                                    # 
                                    fun break_drawoplist_into_mono_gc_drawoplists  ([]: List(w2x::Draw_Op),  results)
                                            =>
                                            reverse results;                                                            # No more input -- done.  Reverse to restore original order.

                                        break_drawoplist_into_mono_gc_drawoplists
                                            ( drawoplist as (first_op ! _),                                             # Input drawops list.
                                              results                                                                   # Batch accumulator.
                                            )
                                            =>
                                            {   (find_max_mono_gc_prefix (drawoplist, NO_GC, first_op.pen, 0u0, []))
                                                    ->
                                                    (remaining_drawoplist, gc_usage, pen, mask, max_prefix: List( { to: xt::Xid, op: w2x::x::Op }));

                                                break_drawoplist_into_mono_gc_drawoplists (remaining_drawoplist, (gc_usage, pen, mask, max_prefix) ! results);
                                            }
                                            where
                                                fun gc_usage_of (w2x::x::CLEAR_AREA _)                =>   NO_GC;
                                                    gc_usage_of (w2x::x::POLY_TEXT8  (font_id, _, _)) =>   WITH_FONT font_id;
                                                    gc_usage_of (w2x::x::POLY_TEXT16 (font_id, _, _)) =>   WITH_FONT font_id;
                                                    gc_usage_of (w2x::x::IMAGE_TEXT8 (font_id, _, _)) =>   SET_FONT  font_id;
                                                    gc_usage_of _                                     =>   NO_FONT;
                                                end;

                                                #
                                                fun extend_mask (m, op)
                                                    =
                                                    m | (pen_vals_used op);


                                                # We are given a list of X drawing operations to do.
                                                # Our job is to find the maximal prefix of this list
                                                # which can all use the same graphics context:
                                                # 
                                                fun find_max_mono_gc_prefix (arg as ([]: List(w2x::Draw_Op), _, _, _, _))
                                                        =>
                                                        arg;

                                                    find_max_mono_gc_prefix (arg as ( ({ to, pen, op }) ! rest, gc_usage, first_pen, used_mask, prefix))
                                                        =>
                                                        if (not (pen_eq (pen, first_pen)))
                                                            #
                                                            arg;
                                                        else
                                                            case (gc_usage, gc_usage_of op)
                                                                #
                                                                (_, NO_GC)
                                                                    =>
                                                                    find_max_mono_gc_prefix (rest, gc_usage, first_pen, used_mask,                                { to, op } ! prefix);

                                                                (NO_GC, new_gc_usage)
                                                                    =>
                                                                    find_max_mono_gc_prefix (rest, new_gc_usage, first_pen, pen_vals_used op,                     { to, op } ! prefix);

                                                                (_, NO_FONT)
                                                                    =>
                                                                    find_max_mono_gc_prefix (rest, gc_usage, first_pen, extend_mask (used_mask, op),              { to, op } ! prefix);

                                                                (SET_FONT font_id, WITH_FONT _)
                                                                    =>
                                                                    find_max_mono_gc_prefix (rest, SET_FONT font_id, first_pen, extend_mask (used_mask, op),      { to, op } ! prefix);

                                                                (_, WITH_FONT font_id)
                                                                    =>
                                                                    find_max_mono_gc_prefix (rest, WITH_FONT font_id, first_pen, extend_mask (used_mask, op),     { to, op } ! prefix);

                                                                (SET_FONT font_id1, SET_FONT font_id2)
                                                                    =>
                                                                    if (font_id1 == font_id2)
                                                                        #
                                                                        find_max_mono_gc_prefix (rest, SET_FONT font_id1, first_pen, extend_mask (used_mask, op), { to, op } ! prefix);
                                                                    else
                                                                        arg;
                                                                    fi;

                                                                (_, SET_FONT font_id)
                                                                    =>
                                                                    find_max_mono_gc_prefix (rest, SET_FONT font_id, first_pen, extend_mask (used_mask, op),      { to, op } ! prefix);
                                                            esac;
                                                        fi;
                                                end;
                                            end;        
                                    end;                                                # fun break_drawoplist_into_mono_gc_drawoplists

                                    #
                                    stipulate



                                        xid0 =   xt::xid_from_unt  0u0;
                                    herein

                                        #
                                        fun encode_and_send_mono_gc_drawoplist (NO_GC,  pen: pg::Pen,  mask: Unt,  ops: List( { to: xt::Xid, op: w2x::x::Op }))
                                                =>
                                                encode_drawops_as_xrequests { gc_id => xid0, font_id => xid0, ops };

                                            encode_and_send_mono_gc_drawoplist (NO_FONT, pen, used_mask, ops)
                                                =>
                                                {   gc_id =  allot_gc { pen, used_mask, note_xrequest };

                                                    encode_drawops_as_xrequests { gc_id, font_id => xid0, ops };

                                                    free_gc  gc_id;
                                                };

                                            encode_and_send_mono_gc_drawoplist (WITH_FONT font_id, pen, used_mask, ops)
                                                =>
                                                {   (allot_gc_with_font { pen, used_mask, note_xrequest, font_id })
                                                        ->
                                                        { gc_id, font_id };

                                                    encode_drawops_as_xrequests { gc_id, font_id, ops };

                                                    free_gc_and_font  gc_id;
                                                };

                                            encode_and_send_mono_gc_drawoplist (SET_FONT font_id, pen, used_mask, ops)
                                                =>
                                                {   gc_id =  allot_gc_and_set_font { pen, used_mask, note_xrequest, font_id };
                                                    #
                                                    encode_drawops_as_xrequests { gc_id, font_id, ops };

                                                    free_gc_and_font  gc_id;
                                                };
                                        end;
                                    end;
                                end)                                                                                    # fun do_drawoplist
                        );

                        get_from_oneshot  reply_1shot;                                                                  # Per top-of-file comments, it is critically important we not return until all xrequests have been registered with the xserver-ximp.
                    };                                                                                                  # This is why we wait on the result oneshot even though there is no return value.

                #
                fun destroy_window              (window_id: xt::Window_Id)
                    =
                    {   reply_1shot =  make_oneshot_maildrop():  Oneshot_Maildrop( Void );
                        #
                        put_in_mailqueue  (client_q,
                            #
                            \\ ({ me, imports, ... }: Runstate)
                                =
# p::DESTROY_WINDOW (wid, reply_oneshot)
#                           fun do_destroy_window  (window_id: xt::Window_Id, reply_1shot: Oneshot_Maildrop(Void))
#                               =
                                {   note_xrequest  (v2w::encode_destroy_window { window_id });
                                    send_pending_xrequests imports;                                                     # Per top-of-file comments, it is critically important we complete send_pending_xrequests before doing our terminal put_in_oneshot() call.
                                    put_in_oneshot (reply_1shot, ());
                                }
                        );

                        get_from_oneshot  reply_1shot;                                                                  # Per top-of-file comments, it is critically important we not return until all xrequests have been registered with the xserver-ximp.
                    };                                                                                                  # This is why we wait on the result oneshot even though there is no return value.
                #
                fun destroy_pixmap              (pixmap: xt::Pixmap_Id)
                    =
                    {   reply_1shot =  make_oneshot_maildrop():  Oneshot_Maildrop( Void );
                        #
                        put_in_mailqueue  (client_q,
                            #
                            \\ ({ me, imports, ... }: Runstate)
                                =
                                {   note_xrequest  (v2w::encode_free_pixmap    { pixmap    });
                                    send_pending_xrequests imports;                                                     # Per top-of-file comments, it is critically important we complete send_pending_xrequests before doing our terminal put_in_oneshot() call.
                                    put_in_oneshot (reply_1shot, ());
                                }
                        );

                        get_from_oneshot  reply_1shot;                                                                  # Per top-of-file comments, it is critically important we not return until all xrequests have been registered with the xserver-ximp.
                    };                                                                                                  # This is why we wait on the result oneshot even though there is no return value.
                #
                fun find_else_open_font (name: String)
                    =
                    {
                        reply_oneshot = make_oneshot_maildrop():  Oneshot_Maildrop( Null_Or( fb::Font ) );
                        #
                        put_in_mailqueue  (client_q,
                            #
                            \\ ({ me, imports, next_xid, to, xdisplay, ... }: Runstate)
                                =
                                case (fx::find_font me.font_index name)
                                    #
                                    result as (THE font)
                                        =>  {
                                                send_pending_xrequests imports;                                         # Per top-of-file comments, it is critically important we complete send_pending_xrequests before doing our terminal put_in_oneshot() call.
                                                put_in_oneshot (reply_oneshot, result);
                                            };  

                                    NULL => {   font_id = next_xid ();
                                                #
                                                imports.xclient_to_sequencer.send_xrequest (v2w::encode_open_font { font => font_id, name });

                                                query = v2w::encode_query_font { font => font_id };

                                                imports.xclient_to_sequencer.send_xrequest_and_pass_reply query to {.
                                                    #
                                                    font_query_reply =  w2v::decode_query_font_reply #reply;

                                                    font = fx::make_font (font_id, xdisplay, font_query_reply);

                                                    fx::note_font me.font_index (name, font);

                                                    send_pending_xrequests imports;                                     # Per top-of-file comments, it is critically important we complete send_pending_xrequests before doing our terminal put_in_oneshot() call.

                                                    put_in_oneshot (reply_oneshot, THE font);
                                                };
                                            };
                                esac
                        );

                        get_from_oneshot  reply_oneshot;                                                                # Per top-of-file comments, it is critically important we not return until all xrequests have been registered with the xserver-ximp.
                    };  
            end;


        fun process_options (options: List(Option), { name })
            =
            {   my_name   = REF name;
                #
                apply  do_option  options
                where
                    fun do_option (MICROTHREAD_NAME n)  =   my_name := n;
                end;

                { name => *my_name };
            };


        ##########################################################################################
        # PUBLIC.
        #
        # (See overview comments at top of file.)
        #
        fun make_xserver_egg                                                                                            # PUBLIC. PHASE 1: Construct our state and initialize from 'options'.
            (
              xdisplay:         dy::Xdisplay,
              drawable:         xt::Drawable_Id,
              options:          List(Option)
            )
            =
            {   (process_options (options, { name => "xserver" }))
                    ->
                    { name };
        
                me =      {
                            hostwindow_is_mapped =>  REF FALSE,
                            font_index          =>  fx::make_font_index ()
                          };


                \\ () = {   reply_oneshot = make_oneshot_maildrop():  Oneshot_Maildrop( (Me_Slot, Exports) );           # PUBLIC. PHASE 2: Start our microthread and return our Exports to caller.
                            #
                            xlogger::make_thread  name  (startup  reply_oneshot);                                       # Note that startup() is curried.

                            (get_from_oneshot  reply_oneshot) -> (me_slot, exports);

                            fun phase3                                                                                  # PUBLIC. PHASE 3: Accept our Imports, then wait for Run_Gun to fire.
                                (
                                  imports:      Imports,
                                  run_gun':     Run_Gun,        
                                  end_gun':     End_Gun
                                )
                                =
                                {
                                    put_in_mailslot  (me_slot, { me, imports, run_gun', end_gun', xdisplay, drawable });
                                };

                            (exports, phase3);
                        };
            };
    };                                          # package xserver_ximp
end;




Comments and suggestions to: bugs@mythryl.org

PreviousUpNext