PreviousUpNext

15.4.1662  src/lib/x-kit/xclient/src/window/xsession-junk.pkg

## xsession-junk.pkg
#
# This package has the highest-level responsibility for
# managing all the state and operations relating to
# communication with a given X server.
#
#
# Architecture
# ------------
#
# Nomenclature:  An 'imp' is a server microthread.
#                (Like a daemon but smaller!)
#
#                A 'ximp' is an X-specific imp. 
#
# An xsocket  is built of four  imps.
# An xsession adds three more   imps to make seven imps total.
# An xclient  adds two   more   imps to make nine  imps total.
# An X application adds an unbounded number of additional widget imps.
#
# Adapting from the page 8 diagram in
#     http://mythryl.org/pub/exene/1991-ml-workshop.pdf
# our dataflow network for xsession looks like:
#
#       ----------------------
#       |  X server process  |
#       ----------------------
#            ^          |
#            |          v
#   -------<network socket>------------- network and process boundary.
#            ^          |xpackets
#            |xpackets  v                                          ---           ---              ---
#  --------------- ---------------                                  .             .                .
#  | outbuf_ximp | | inbuf_ximp  |                                  .             .                .
#  --------------- ---------------                                  .             .                .
#        ^             | xpackets                                   .             .                .
#        | xpackets    v                                            .             .                .
#  -------------------------------                                  .             .                .
#  |     xsequencer_ximp         |--> (error handler)               ... xsocket   .                .
#  -------------------------------                                  .   imps      .                .
#              ^                | xpackets                          .             .                .
#              |                v                                   .             ... xsession     .
#              |             -------------------------              .             .   imps         .
#              |             | decode_xpackets_ximp  |              .             .                .
#              |             -------------------------              .             .                .
#              |                | xevents                          ---            .                .
#              |                v                                                 .                .
#              |             -------------------------    ---------------         .                .
#              |             | xevent_router_ximp |--> | keymap_ximp |         .                .
#              |             -------------------------    ---------------         .                .
#              |                | xevents  ^                    ^                 .                .... xclient
#              |                |          |                    |                 .                .    imps
#              |                |          |                    |                 .                .
#              |                |          |                    |                ---               .
#  -------------------------    |          |                    |                                  .
#  |      xserver_ximp     |    |          |                    |                                  .
#  -------------------------    |          |                    |                                  .
#              ^                |          |get_window_site     |                                  .
#              |                | xevents  |note_new_hostwindow  |                                 ---
#              |                v          |                    v
# (.................................to/from widget threads......................................)
#        ^                |               ^                |              ^                |         
#        |xrequests       | xevents       |xrequests       | xevents      |xrequests       | xevents   
#        |                v               |                v              |                v         
#     -------------------------        -------------------------       -------------------------                     
#     | xevent_to_widget_ximp |        | xevent_to_widget_ximp |       | xevent_to_widget_ximp |    ...
#     -------------------------        -------------------------       -------------------------                     
#             /      \                         /      \                        /      \              
#            / widget \                       / widget \                      / widget \                             
#           /   tree   \                     /   tree   \                    /   tree   \            
#          /            \                   /            \                  /            \           
#         /     ...      \                 /     ...      \                /     ...      \            
#
# Dramatis Personae:
#
#  o  The sequencer_imp matches replies to requests.
#     All traffic to/from the X server goes through it.
#         Implemented in:  src/lib/x-kit/xclient/src/wire/xsequencer-ximp.pkg
#
#  o  The outbuf_imp optimizes network usage by
#     combining multiple requests per network packet.
#         Implemented in:  src/lib/x-kit/xclient/src/wire/outbuf-ximp.pkg
#
#  o  The inbuf_imp breaks the incoming bytestream
#     into individual replies and forwards them individually
#     to sequencer_imp.
#         Implemented in:  src/lib/x-kit/xclient/src/wire/inbuf-ximp.pkg
#
#  o  The decode_xpackets_imp cracks raw wire-format bytestrings into
#     xevent_types::x::Event values and combines multiple related Expose
#     events into a single logical Expose event for ease of downstream
#     processing.
#         Implemented in:  src/lib/x-kit/xclient/src/wire/decode-xpackets-ximp.pkg
#
#  o  The   xevent_to_window_imp   imp receives all X events
#     (e.g. keystrokes and mouseclicks) and feeds each one to the
#     appropriate toplevel window, or more precisely to the
#     hostwindow_to_widget_router   at the root of the widgettree for
#   ("xevent_to_widget_imp" might be a better name)
#     that window, there to trickle down the widgettree to its ultimate
#     target widget.
#
#     To do this, xevent_to_window_imp
#     tracks all X windows created by the application,
#     keyed by their X IDs.  (Toplevel X windows are
#     registered at creation by the window-old.pkg functions;
#     subwindows are registered when their X notify event
#     comes through.)
#
#         Implemented in:  src/lib/x-kit/xclient/src/window/xevent-router-ximp.pkg
#         See also:        src/lib/x-kit/xclient/src/window/xevent-to-widget-ximp.pkg
#
#  o  The font_imp ...
#         Implemented in:  src/lib/x-kit/xclient/src/window/font-index.pkg
#
#  o  The keymap_ximp ...
#         Implemented in:  src/lib/x-kit/xclient/src/window/keymap-ximp.pkg
#
#
#  o  The xserver_ximp processes draw commands and breaks
#     them into subsequences which can share a single
#     X server graphics context, in order to minimize
#     the number of graphics context switches required.
#     It works closely with the pen-to-gcontext-imp.
#         Implemented in:  src/lib/x-kit/xclient/src/window/xserver-ximp.pkg
#
#  o  The pen_cache maps between the immutable "pens"
#     we provide to the application programmer and the mutable
#     graphics contexts actually supported by the X server. Given
#     a pen, it returns a matching graphics context, using an
#     existing one unchanged if possible, else modifying an
#     existing one appropropriately.
#         Implemented in:  src/lib/x-kit/xclient/src/window/pen-cache.pkg
#
#
# All mouse and keyboard events flow down through the
# inbuf, sequencer, decoder and xevent-to-window imps
# and thence down through the widget hierarchy
# associated with the relevant hostwindow.
#
# Client xserver requests and responses are sent
# directly to the sequencer imp, with the exception
# of font requests and responses, which run through
# the font imp.
#
# Keysym translations are handled by keymap_ximp.

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





###                "I have always wished that my computer
###                 would be as easy to use as my telephone.
###                 My wish has come true ... I no longer
###                 know how to use my telephone."
###
###                               -- Bjarne Stroustrup



stipulate
    include package   threadkit;                        # threadkit                             is from   src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg
    #
    package ax  =  atom_ximp;                           # atom_ximp                             is from   src/lib/x-kit/xclient/src/iccc/atom-ximp.pkg
    package g2d =  geometry2d;                          # geometry2d                            is from   src/lib/std/2d/geometry2d.pkg
    package cs  =  color_spec;                          # color_spec                            is from   src/lib/x-kit/xclient/src/window/color-spec.pkg
    package kab =  keys_and_buttons;                    # keys_and_buttons                      is from   src/lib/x-kit/xclient/src/wire/keys-and-buttons.pkg
    package v2w =  value_to_wire;                       # value_to_wire                         is from   src/lib/x-kit/xclient/src/wire/value-to-wire.pkg
    package s2w =  sendevent_to_wire;                   # sendevent_to_wire                     is from   src/lib/x-kit/xclient/src/wire/sendevent-to-wire.pkg
    package w2v =  wire_to_value;                       # wire_to_value                         is from   src/lib/x-kit/xclient/src/wire/wire-to-value.pkg
    package xt  =  xtypes;                              # xtypes                                is from   src/lib/x-kit/xclient/src/wire/xtypes.pkg
    package xtr =  xlogger;                             # xlogger                               is from   src/lib/x-kit/xclient/src/stuff/xlogger.pkg
    package clx =  xclient_ximps;                       # xclient_ximps                         is from   src/lib/x-kit/xclient/src/window/xclient-ximps.pkg
    package wpx =  window_watcher_ximp;                 # window_watcher_ximp                   is from   src/lib/x-kit/xclient/src/window/window-watcher-ximp.pkg
    package sel =  selection_ximp;                      # selection_ximp                        is from   src/lib/x-kit/xclient/src/window/selection-ximp.pkg

# Not visible here:
#    package qk  =  quark;                              # quark                                 is from   src/lib/x-kit/style/quark.pkg
#    package imx =  image_ximp;                         # image_ximp                            is from   src/lib/x-kit/widget/lib/image-ximp.pkg
#    package rpx =  ro_pixmap_ximp;                     # ro_pixmap_ximp                        is from   src/lib/x-kit/widget/lib/ro-pixmap-ximp.pkg
#    package shx =  shade_ximp;                         # shade _ximp                           is from   src/lib/x-kit/widget/lib/shade-ximp.pkg


    package mop =  mailop;                              # mailop                                is from   src/lib/src/lib/thread-kit/src/core-thread-kit/mailop.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

#    package dt  =  draw_types;                         # draw_types                            is from   src/lib/x-kit/xclient/src/window/draw-types.pkg

#    package rwp =  rw_pixmap;                          # rw_pixmap                             is from   src/lib/x-kit/xclient/src/window/rw-pixmap.pkg

#   package dy  =  display_old;                         # display_old                           is from   src/lib/x-kit/xclient/src/wire/display-old.pkg
    package dy  =  display;                             # display                               is from   src/lib/x-kit/xclient/src/wire/display.pkg

#   package fti =  font_imp_old; # "fi" is taken! :-)   # font_imp_old                          is from   src/lib/x-kit/xclient/src/window/font-imp-old.pkg
    package fti =  font_index;                          # font_index                            is from   src/lib/x-kit/xclient/src/window/font-index.pkg

#   package s2t =  xsocket_to_hostwindow_router_old;    # xsocket_to_hostwindow_router_old      is from   src/lib/x-kit/xclient/src/window/xsocket-to-hostwindow-router-old.pkg
    package s2t =  xevent_router_ximp;                  # xevent_router_ximp                    is from   src/lib/x-kit/xclient/src/window/xevent-router-ximp.pkg
    package a2r =  windowsystem_to_xevent_router;       # windowsystem_to_xevent_router         is from   src/lib/x-kit/xclient/src/window/windowsystem-to-xevent-router.pkg
    #
#   package xok =  xsocket_old;                         # xsocket_old                           is from   src/lib/x-kit/xclient/src/wire/xsocket-old.pkg
    package x2s =  xclient_to_sequencer;                # xclient_to_sequencer                  is from   src/lib/x-kit/xclient/src/wire/xclient-to-sequencer.pkg
    package sj  =  socket_junk;                         # socket_junk                           is from   src/lib/internet/socket-junk.pkg

#   package ai  =  atom_imp_old;                        # atom_imp_old                          is from   src/lib/x-kit/xclient/src/iccc/atom-imp-old.pkg
    package ai  =  atom_ximp;                           # atom_ximp                             is from   src/lib/x-kit/xclient/src/iccc/atom-ximp.pkg
    package ap  =  client_to_atom;                              # client_to_atom                                is from   src/lib/x-kit/xclient/src/iccc/client-to-atom.pkg

#   package di  =  draw_imp_old;                        # draw_imp_old                          is from   src/lib/x-kit/xclient/src/window/draw-imp-old.pkg
    package di  =  xserver_ximp;                        # xserver_ximp                          is from   src/lib/x-kit/xclient/src/window/xserver-ximp.pkg

#   package ki  =  keymap_imp_old;                      # keymap_imp_old                        is from   src/lib/x-kit/xclient/src/window/keymap-imp-old.pkg
    package ki  =  keymap_ximp;                         # keymap_ximp                           is from   src/lib/x-kit/xclient/src/window/keymap-ximp.pkg
    package r2k =  xevent_router_to_keymap;             # xevent_router_to_keymap               is from   src/lib/x-kit/xclient/src/window/xevent-router-to-keymap.pkg

    package w2x =  windowsystem_to_xserver;             # windowsystem_to_xserver               is from   src/lib/x-kit/xclient/src/window/windowsystem-to-xserver.pkg
    package exx =  xserver_ximp;                        # xserver_ximp                          is from   src/lib/x-kit/xclient/src/window/xserver-ximp.pkg

#   package si  =  selection_imp_old;                   # selection_imp_old                     is from   src/lib/x-kit/xclient/src/window/selection-imp-old.pkg
    package si  =  selection_ximp;                      # selection_ximp                        is from   src/lib/x-kit/xclient/src/window/selection-ximp.pkg
    package sep =  client_to_selection;                 # client_to_selection                   is from   src/lib/x-kit/xclient/src/window/client-to-selection.pkg

#   package wpi =  window_property_imp_old;             # window_property_imp_old               is from   src/lib/x-kit/xclient/src/window/window-property-imp-old.pkg
    package wpi =  window_watcher_ximp;                 # window_watcher_ximp                   is from   src/lib/x-kit/xclient/src/window/window-watcher-ximp.pkg
    package wpp =  client_to_window_watcher;            # client_to_window_watcher              is from   src/lib/x-kit/xclient/src/window/client-to-window-watcher.pkg
    #
    trace =  xtr::log_if  xtr::io_logging  0;           # Conditionally write strings to tracing.log or whatever.
herein


    package   xsession_junk
    :         Xsession_Junk                             # Xsession_Junk                         is from   src/lib/x-kit/xclient/src/window/xsession-junk.api
    {
        Per_Depth_Imps =      {                                                                         # The pen-cache and draw_ximp for a given depth, visual and screen.
                                depth:                          Int,
                                windowsystem_to_xserver:        w2x::Windowsystem_To_Xserver,           # The xpacket encoder  for this depth on this screen.
                                window_map_event_sink:          wme::Window_Map_Event_Sink
                              };                                                                        #
                                                                                                        # For each combination of visual and depth
                                                                                                        # we allot a pair of imps, one to draw,
                                                                                                        # one to manage graphics contexts.
                                                                                                        #   This is forced because X requires that
                                                                                                        # each GraphicsContext and pixmap be associated
                                                                                                        # with a particular screen, visual and depth.
        Screen_Info =         {
                                xscreen:                        dy::Xscreen,                            # Xscreen       def in    src/lib/x-kit/xclient/src/wire/display.pkg
                                per_depth_imps:                 List( Per_Depth_Imps ),                 # The pen-cache and draw imps for the supported depths on this screen.
                                rootwindow_per_depth_imps:            Per_Depth_Imps                    # The pen-cache and draw imps for the root window on this screen.
                              };


        Xsession =            {
                                xdisplay:                       dy::Xdisplay,                           #  
                                screens:                        List( Screen_Info ),

                                default_screen_info:            Screen_Info,

                                windowsystem_to_xevent_router:  a2r::Windowsystem_To_Xevent_Router,     # Feeds X events to appropriate toplevel window.

                                font_index:                     fti::Font_Index,
                                client_to_atom:                 ap::Client_To_Atom,

                                client_to_window_watcher:       wpp::Client_To_Window_Watcher,
                                client_to_selection:            sep::Client_To_Selection,
                                windowsystem_to_xserver:        w2x::Windowsystem_To_Xserver,
                                xevent_router_to_keymap:        r2k::Xevent_Router_To_Keymap
                              };

        Screen =              {                                                                         # A screen handle for users.
                                xsession:                       Xsession,
                                screen_info:                    Screen_Info
                              };

        Rw_Pixmap =           {                                                                         # An off-screen rectangular array of pixels on the X server.
                                pixmap_id:                      xt::Pixmap_Id,
                                screen:                         Screen,
                                size:                           g2d::Size,
                                per_depth_imps:                 Per_Depth_Imps
                              };

        Ro_Pixmap = RO_PIXMAP  Rw_Pixmap;                                                               # Immutable pixmaps 

        #
        Window =                                                                                        # An on-screen rectangular array of pixels on the X server.
                              {
                                window_id:                      xt::Window_Id,
                                #
                                screen:                         Screen,
                                per_depth_imps:                 Per_Depth_Imps,
                                #
                                windowsystem_to_xserver:        w2x::Windowsystem_To_Xserver,
                                #
                                subwindow_or_view:              Null_Or( Rw_Pixmap )
                              };

        # Identity tests:
        #
        fun same_xsession
            ( { xdisplay=>{ socket => x1, ... }: dy::Xdisplay, ... }: Xsession,
              { xdisplay=>{ socket => x2, ... }: dy::Xdisplay, ... }: Xsession
            )
            =
            (x1 == x2);
#           xok::same_xsocket (x1, x2); # Repply had this
        #
        fun same_screen ( { xsession=>xsession1, screen_info=> { xscreen => { id=>id1, ... }: dy::Xscreen, ... }: Screen_Info }: Screen,
                          { xsession=>xsession2, screen_info=> { xscreen => { id=>id2, ... }: dy::Xscreen, ... }: Screen_Info }: Screen
                        )
            =
            (id1 == id2)
            and
            same_xsession (xsession1, xsession2);
        #
        fun same_window (   { window_id=>id1, screen=>s1, ... }: Window,
                            { window_id=>id2, screen=>s2, ... }: Window   )
            =
           (id1 == id2) and same_screen (s1, s2);

        # We are typically called from   open_xsession()   below:
        #
        fun make_per_screen_xsession_imps                                               # This fn is currently private to this file.
              {
                run_gun':                       mop::Run_Gun,
                end_gun':                       mop::End_Gun,
                windowsystem_to_xevent_router:  a2r::Windowsystem_To_Xevent_Router,     # Directs X mouseclicks etc to right hostwindow.
                windowsystem_to_xserver:        w2x::Windowsystem_To_Xserver,           # Everyone but xserver-imp should use this instead of xclient_to_sequencer.
                xclient_to_sequencer:           x2s::Xclient_To_Sequencer,              # All drawing commands go to Xserver via sequencer then outbuf.
                client_to_atom:                 ap::Client_To_Atom,
                xevent_router_to_keymap:        r2k::Xevent_Router_To_Keymap,
                client_to_selection:            sep::Client_To_Selection,
                client_to_window_watcher:       wpp::Client_To_Window_Watcher,
                xdisplay:                       dy::Xdisplay,
                drawable:                       xt::Drawable_Id

# display_name:     String,
#              xauthentication:  Null_Or( xt::Xauthentication )                         # Xauthentication info comes ultimately from ~/.Xauthority
              }
            =
            {
# printf "make_xsession/AAA  -- xsession-junk.pkg\n";
                # We turn this off in close_xession, so for symmetry's
                # sake we turn it on here in open_xsession:
                #                                                                       # tracing               is from   src/lib/src/lib/thread-kit/src/lib/logger.pkg
#               logger::disable  thread_deathwatch::logging;                            # thread_deathwatch     is from   src/lib/src/lib/thread-kit/src/lib/thread-deathwatch.pkg


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


                font_index =  fti::make_font_index ();

                #
                fun make_screen_info (xscreen as { root_window_id, root_visual, visuals, ... }: dy::Xscreen )
                    =
                    {   fun make_per_depth_imps  (depth, drawable)
                            =
                            {
#                               drawimp_mappedstate_slot =  make_mailslot ();
#                               make_thread  "send FIRST_EXPOSE"  {.   put_in_mailslot (drawimp_mappedstate_slot, di::s::FIRST_EXPOSE);   };

                                (exx::make_xserver_egg (xdisplay, drawable, [])) ->   xserver_egg;
                                (xserver_egg ()) ->  (exports, xserver_egg');

                                xserver_egg' ({ windowsystem_to_xevent_router, xclient_to_sequencer }, run_gun', end_gun');
                                
                                windowsystem_to_xserver =   exports.windowsystem_to_xserver;
                                window_map_event_sink   =   exports.window_map_event_sink;

                                { depth, windowsystem_to_xserver, window_map_event_sink }: Per_Depth_Imps;
                            };
                        #
                        fun make_pen_imps ([], l)
                                =>
                                l;

                            make_pen_imps (vd ! r, l)
                                =>
                                make_pen_imps (r, get l)
                                where
                                    visual_depth =  dy::depth_of_visual  vd;
                                    #
                                    fun make_imps ()
                                        =
                                        {   pixmap_id = next_xid ();

                                            # Make a pixmap to serve as the  witness drawable
                                            # for the graphics context ("GC") server:
                                            #
                                            windowsystem_to_xserver.xclient_to_sequencer.send_xrequest
                                              ( v2w::encode_create_pixmap
                                                  { pixmap_id,
                                                    drawable_id =>  root_window_id,
                                                    size        =>  { wide=>1, high=>1 },
                                                    depth       =>  visual_depth
                                                  }
                                              );

                                            make_per_depth_imps (visual_depth, pixmap_id);
                                        };

                                    #
                                    fun get [] =>   make_imps() ! l;
                                        #
                                        get (({ depth, ... }: Per_Depth_Imps)  ! rest)
                                            =>
                                            depth == visual_depth
                                             ??  l
                                             ::  get rest;
                                    end;
                                end;
                        end;

                        rootwindow_per_depth_imps
                            =
                            make_per_depth_imps  (dy::depth_of_visual  root_visual,  root_window_id);

                        per_depth_imps
                            =
                            make_pen_imps (visuals, [ rootwindow_per_depth_imps ]);

                        per_depth_imps
                            =
                            make_pen_imps ( [ xt::NO_VISUAL_FOR_THIS_DEPTH 1 ],
                                            per_depth_imps
                                          );

                        { xscreen,
                          per_depth_imps,
                          rootwindow_per_depth_imps
                        }
                        : Screen_Info
                        ;
                    };                                          # fun make_screen_info

                screens =  map  make_screen_info  screens;

# printf "make_xsession/ZZZ  -- xsession-junk.pkg\n";
                  {
                    xdisplay,
                    default_screen_info =>  list::nth (screens, default_screen),
                    screens,
                    windowsystem_to_xevent_router,
                    client_to_atom,
                    font_index,
                    client_to_window_watcher,
                    client_to_selection,
                    windowsystem_to_xserver,
#                   xclient_to_sequencer,
                    xevent_router_to_keymap
                  }: Xsession;
          };                                                    # fun make_per_screen_xsession_imps


        # We are typically called from   make_root_window()   in
        #
        #     src/lib/x-kit/widget/lib/root-window.pkg
        #
        fun open_xsession
              {
                display_name:           String,
                xauthentication:        Null_Or( xt::Xauthentication ),
                run_gun':               mop::Run_Gun,
                end_gun':               mop::End_Gun
              }
            =
            {
# printf "open_xsession/AAA calling   open_xdisplay  display_name s='%s'  -- xsession-junk.pkg\n" display_name;
                (dy::open_xdisplay { display_name, xauthentication })
                    ->
                    (xdisplay as { default_screen, screens, socket, next_xid, ... }: dy::Xdisplay );    # Canonical sequence has 'xsocket' not 'socket' here.
# printf "open_xsession/BBB back from open_xdisplay  display_name s='%s'  -- xsession-junk.pkg\n" display_name;

                
                default_screen =    list::nth (screens, default_screen)
                                    except
                                        INDEX_OUT_OF_BOUNDS = {   msg = "Bad default_screen value -- make_root_window in xclient-ximps-junk.pkg";
                                                        log::fatal msg;                 # Doesn't return.
                                                        raise exception DIE msg;        # Should never get here.
                                                    };

                default_screen ->   { root_window_id, ... }: dy::Xscreen;

#               (make_run_gun ()) ->   { run_gun', fire_run_gun };
#               (make_end_gun ()) ->   { end_gun', fire_end_gun };


                (clx::make_xclient_ximps_egg   (socket, xdisplay, root_window_id, [])) ->   xclient_ximps_egg;

                (xclient_ximps_egg  ()) ->  (xclient_ximps_exports, xclient_ximps_egg');

                (ax::make_atom_egg                    []  ) ->   atom_egg;
                (atom_egg                             ()  ) ->  (atom_exports, atom_egg');

                (wpx::make_window_watcher_egg         []  ) ->   window_watcher_egg;
                (window_watcher_egg                   ()  ) ->  (window_watcher_exports, window_watcher_egg');

                (sel::make_selection_egg []               ) ->   selection_egg;
                (selection_egg ()                         ) ->  (selection_exports, selection_egg');


                xclient_ximps_exports -> { windowsystem_to_xserver, windowsystem_to_xevent_router, xevent_router_to_keymap, xclient_to_sequencer, xerror_well };

                xclient_to_sequencer            =         windowsystem_to_xserver.xclient_to_sequencer;

                client_to_window_watcher        =  window_watcher_exports.client_to_window_watcher;
                window_property_xevent_sink     =  window_watcher_exports.window_property_xevent_sink;

                client_to_selection             =        selection_exports.client_to_selection;
                selection_xevent_sink           =        selection_exports.selection_xevent_sink;


                client_to_atom                  =             atom_exports.client_to_atom;




# not visible here.
#
# TBD: image_ximp           configuration

#               window_property_xevent_sink =   { put_value =>  (\\ (event: et::x::Event) = { log::fatal  "window_property_xevent_sink called"; (); }) };       # Dummy to 'handle' X server PropertyNotify events.
#               selection_xevent_sink       =   { put_value =>  (\\ (event: et::x::Event) = { log::fatal  "selection_xevent_sink called"      ; (); }) };       # Dummy to 'handle' X server SelectionNotify, SelectionRequest and SelectionClear events.

                xclient_ximps_egg'    ( { window_property_xevent_sink, selection_xevent_sink },
                                        run_gun', end_gun'
                                      );

                atom_egg'             ( { xclient_to_sequencer },               # XXX SUCKO FIXME probably we should pass  windowsystem_to_xserver  not  xclient_to_sequencer  here -- we want to encourage everyone but  xserver to avoid using xclient_to_sequencer to avoid race conditions.
                                        run_gun', end_gun'
                                      );

                window_watcher_egg'   ( { client_to_atom /* , xclient_to_sequencer */ },
                                        run_gun', end_gun'
                                      );

                selection_egg'        ( { xclient_to_sequencer },               # XXX SUCKO FIXME probably we should pass  windowsystem_to_xserver  not  xclient_to_sequencer  here -- we want to encourage everyone but  xserver to avoid using xclient_to_sequencer to avoid race conditions.
                                        run_gun', end_gun'
                                      );


                xsession =  make_per_screen_xsession_imps
                              {
                                run_gun',
                                end_gun',
                                windowsystem_to_xevent_router,
                                windowsystem_to_xserver,
                                xclient_to_sequencer,                           # XXX SUCKO FIXME probably we should pass  windowsystem_to_xserver  not  xclient_to_sequencer  here -- we want to encourage everyone but  xserver to avoid using xclient_to_sequencer to avoid race conditions.
                                client_to_atom,
                                xevent_router_to_keymap,
                                client_to_selection,
                                client_to_window_watcher,
                                xdisplay,
                                drawable => root_window_id
                              };


# printf "open_xsession/ZZZ  -- xsession-junk.pkg\n";
                xsession;
            };                                                  # fun open_xsession


        fun send_xrequest (x: Xsession) request
            =
            x.windowsystem_to_xserver.xclient_to_sequencer.send_xrequest request;                               # XXX SUCKO FIXME probably we should use  windowsystem_to_xserver  not  xclient_to_sequencer  here -- we want to encourage everyone but  xserver to avoid using xclient_to_sequencer to avoid race conditions.

        # X-server I/O.
        #
#       stipulate
#           #
#           fun apply_to_xsocket f ({ xdisplay=>{ xsocket, ... }: dy::Xdisplay, ... }: Xsession )
#                =
#                f xsocket;
#
#       herein
#
#           send_xrequest                     =  apply_to_xsocket  xok::send_xrequest;
#           send_xrequest_and_return_completion_mailop  =  apply_to_xsocket  xok::send_xrequest_and_return_completion_mailop;
#
#           send_xrequest_and_read_reply      =  apply_to_xsocket  xok::send_xrequest_and_read_reply;
#           sent_xrequest_and_read_replies    =  apply_to_xsocket  xok::sent_xrequest_and_read_replies;
#
#           flush_out          =  apply_to_xsocket  xok::flush_xsocket;
#
#           query_best_size    =  apply_to_xsocket  xok::query_best_size;
#           query_colors       =  apply_to_xsocket  xok::query_colors;
#           query_font         =  apply_to_xsocket  xok::query_font;
#           query_pointer      =  apply_to_xsocket  xok::query_pointer;
#           query_text_extents =  apply_to_xsocket  xok::query_text_extents;
#           query_tree         =  apply_to_xsocket  xok::query_tree;
#
#       end;

        # Get location of mouse pointer
        # plus related information:
        #
#       fun get_mouse_location
#           (
#             { xdisplay            =>  { xsocket, ... }: dy::Xdisplay,
#               default_screen_info =>  { xscreen =>  { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
#               ...
#             }: Xsession
#           )
#           =
#           {   # The X server query_pointer call takes a window_id
#               # argument. This seems overcomplex for the typical
#               # Mythryl caller, so here we just default it to the
#               # the default-screen root-window:
#               #
#               (xok::query_pointer  xsocket  { window_id => root_window_id })
#                   ->
#                   { root_point, ... };
#
#               # The X server query_pointer call returns
#               # a load of stuff.  For now at least, a
#               # return value of simply the mouse location
#               # seems more convenient for the Mythryl app hacker:
#               #
#               root_point;
#           };
        #
#       fun set_mouse_location
#           (
#             { xdisplay            =>  { xsocket, ... }: dy::Xdisplay,
#               default_screen_info =>  { xscreen =>  { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
#               ...
#             }: Xsession
#           )
#           to_point
#           =
#           {   # This is an ignored dummy value:
#               #
#               from_box =  { col => 0, row => 0, wide => 0, high => 0 };
#
#               command
#                   =
#                   v2w::encode_warp_pointer
#                      {
#                       to_point,                                       # Move mouse pointer to this coordinate.
#                        to   =>  THE root_window_id,                   # Position mouse relative to root window.
#                       #                                               # (That is, in absolute screen coordinates.)
#                       from =>  NULL,
#                       from_box                                        # Ignored because 'from' is NULL.
#                      };
#
#               xok::send_xrequest  xsocket  command;
#           };

        # Map a point in the window's coordinate
        # system to the screen's coordinate system:
        #
        fun window_point_to_screen_point ({ window_id, screen, ... }: Window ) pt
            =
            {   screen ->  { xsession => (x: Xsession), screen_info => { xscreen => { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info, ... }: Screen;
                #
                my { to_point, ... }
                    =
                    w2v::decode_translate_coordinates_reply
                      (
                        block_until_mailop_fires
#                       ========================                XXX SUCKO FIXME
                          (x.windowsystem_to_xserver.xclient_to_sequencer.send_xrequest_and_read_reply
                              (v2w::encode_translate_coordinates { from_window=>window_id, to_window=>root_window_id, from_point=>pt } )
                          )
                      );

                to_point;
            };

        # Fake up an X server timestamp for the current time
        # by taking the time of day in milliseconds to 32-bit
        # accuracy and then jiggering the type appropriately:
        #
        fun bogus_current_x_timestamp ()
            =
            {    time =  time::get_current_time_utc ();                                         # Current time
                 ms   =  time::to_milliseconds  time;                                           # in milliseconds since the Epoch

                 ms32 =  large_int::(%) (ms,  (large_int::from_int 256)
                                            * (large_int::from_int 256)
                                            * (large_int::from_int 256)
                                            * (large_int::from_int 256));                       # truncated to 32-bit accuracy

                 ms32 =  one_word_unt::from_multiword_int  ms32;                                # converted to 32-bit unsigned

                 ms32 =  xserver_timestamp::XSERVER_TIMESTAMP  ms32;                            # wrapped up as a
                 ms32 =  xtypes::TIMESTAMP ms32;                                                # proper X timestamp value.
                 ms32;
            };  
        #
        fun send_fake_key_press_xevent
            (
              { default_screen_info =>  { xscreen =>  { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
                ...
              }: Xsession
            )
            { window =>  window as { window_id, windowsystem_to_xserver, ... }: Window,         # Window handling the keyboard-key press event.
              keycode,                                                                          # Keyboard key just "pressed".
              point  =>  point as { row, col }                                                  # Keypress location in local window coordinates.
            }
            =
            {   # We need the keypress point in both
                # local and screen coords:
                #
# trace {. sprintf "xsession: send_fake_key_press_event/TOP window_point = { row %d, col %d }." row col; };
                (window_point_to_screen_point  window  point)
                    ->
                    { row => screen_row,
                                col => screen_col
                              };

# trace {. sprintf "xsession: send_fake_key_press_event/MID screen_point = { row %d, col %d }." screen_row screen_col; };
                # For the semantics of these three fields see
                #     p27 http://mythryl.org/pub/exene/X-protocol-R6.pdf
                #
                send_event_to   =  xt::SEND_EVENT_TO_WINDOW  window_id;
                propagate       =  FALSE;
                event_mask      =  xt::EVENT_MASK 0u0;
                #
#               timestamp       =  xt::CURRENT_TIME;                                            # I had thought the X server would fill this in for us, but apparently it passes it through. :-(
                timestamp       =  bogus_current_x_timestamp ();                                # This won't sync with real X server timestamps, but I don't see a simple way to make it do so.
                                                                                                # Currently we never mix synthetic and natural X events, but this is a bug waiting to happen. XXX BUGGO FIXME.
                root_window_id  =  root_window_id;
                event_window_id =  window_id;                                                   # Window handling the keyboard-key "press" event.
                child_window_id =  NULL;                                                        # We'll assume specified window is a leaf.
                root_x          =  screen_col;                                                  # Mouse position on root window at time of keypress.
                root_y          =  screen_row;
                event_x         =  col;                                                         # Mouse position on recipient window at time of keypress.
                event_y         =  row;
                buttons         =  kab::make_mousebutton_state [ ];                             # Mouse buttons state BEFORE keypress.

# trace {. "xsession: send_fake_key_press_event/YYY calling s2w::encode_send_keypress_xevent"; };
                command
                    =
                    s2w::encode_send_keypress_xevent
                      {
                        send_event_to,  propagate,  event_mask,
                        timestamp,  root_window_id,  event_window_id,
                        child_window_id,  root_x,  root_y,
                        event_x,  event_y,  keycode, buttons
                      };

                windowsystem_to_xserver.xclient_to_sequencer.send_xrequest  command;            # Here we used to have          xclient_to_sequencer.send_xrequest  command;
                                                                                                # but to avoid race conditions we prefer nowdays to avoid bypassing xserver.
# trace {. "xsession: send_fake_key_press_event/BOT called  s2w::encode_send_keypress_xevent -- DONE"; };
                ();
            };
        #
        fun send_fake_key_release_xevent
            (
              { default_screen_info =>  { xscreen =>  { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
                ...
              }: Xsession
            )
            { window =>  window as { window_id, windowsystem_to_xserver, ... }: Window,         # Window handling the keyboard-key release event.
              keycode,                                                                          # Keyboard key just "released".
              point  =>  point as { row, col }                                                  # Key release location in local window coordinates.
            }
            =
            {   # We need the key release point in both
                # local and screen coords:
                #
# trace {. sprintf "xsession: send_fake_key_release_event/TOP window_point = { row %d, col %d }." row col; };
                (window_point_to_screen_point  window  point)
                    ->
                    { row => screen_row,
                      col => screen_col
                    };

# trace {. sprintf "xsession: send_fake_key_release_event/MID screen_point = { row %d, col %d }." screen_row screen_col; };
                # For the semantics of these three fields see
                #     p27 http://mythryl.org/pub/exene/X-protocol-R6.pdf
                #
                send_event_to   =  xt::SEND_EVENT_TO_WINDOW  window_id;
                propagate       =  FALSE;
                event_mask      =  xt::EVENT_MASK 0u0;
                #
#               timestamp       =  xt::CURRENT_TIME;                                            # I had thought the X server would fill this in for us, but apparently it passes it through. :-(
                timestamp       =  bogus_current_x_timestamp ();                                # This won't sync with real X server timestamps, but I don't see a simple way to make it do so.
                                                                                                # Currently we never mix synthetic and natural X events, but this is a bug waiting to happen. XXX BUGGO FIXME.
                root_window_id  =  root_window_id;
                event_window_id =  window_id;                                                   # Window handling the keyboard-key "release" event.
                child_window_id =  NULL;                                                        # We'll assume specified window is a leaf.
                root_x          =  screen_col;                                                  # Mouse position on root window at time of key "release".
                root_y          =  screen_row;
                event_x         =  col;                                                         # Mouse position on recipient window at time of key "release".
                event_y         =  row;
                buttons         =  kab::make_mousebutton_state [ ];                             # Mouse buttons state BEFORE key release.

# trace {. "xsession: send_fake_key_release_event/YYY calling s2w::encode_send_keyrelease_xevent"; };
                command
                    =
                    s2w::encode_send_keyrelease_xevent
                      {
                        send_event_to,  propagate,  event_mask,
                        timestamp,  root_window_id,  event_window_id,
                        child_window_id,  root_x,  root_y,
                        event_x,  event_y,  keycode, buttons
                      };

                windowsystem_to_xserver.xclient_to_sequencer.send_xrequest  command;            # Here we used to have          xclient_to_sequencer.send_xrequest  command;
                                                                                                # but to avoid race conditions we prefer nowdays to avoid bypassing xserver.
# trace {. "xsession: send_fake_key_release_event/BOT called  s2w::encode_send_keyrelease_xevent -- DONE"; };
                ();
            };
        #
        fun send_fake_mousebutton_press_xevent
            (
              { default_screen_info =>  { xscreen =>  { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
                ...
              }: Xsession
            )
            { window =>  window as { window_id, windowsystem_to_xserver, ... }: Window,         # Window handling the mouse-button click event.
              button,                                                                           # Mouse button just "clicked" down.
              point  =>  point as { row, col }                                                  # Click location in local window coordinates.
            }
            =
            {   # We need the clickpoint in both
                # local and screen coords:
                #
# trace {. sprintf "xsession: send_fake_mousebutton_press_event/TOP window_point = { row %d, col %d }." row col; };
                (window_point_to_screen_point  window  point)
                    ->
                    { row => screen_row,
                      col => screen_col
                    };

# trace {. sprintf "xsession: send_fake_mousebutton_press_event/MID screen_point = { row %d, col %d }." screen_row screen_col; };
                # For the semantics of these three fields see
                #     p27 http://mythryl.org/pub/exene/X-protocol-R6.pdf
                #
                send_event_to   =  xt::SEND_EVENT_TO_WINDOW  window_id;
                propagate       =  FALSE;
                event_mask      =  xt::EVENT_MASK 0u0;
                #
#               timestamp       =  xt::CURRENT_TIME;                                            # I had thought the X server would fill this in for us, but apparently it passes it through. :-(
                timestamp       =  bogus_current_x_timestamp ();                                # This won't sync with real X server timestamps, but I don't see a simple way to make it do so.
                                                                                                # Currently we never mix synthetic and natural X events, but this is a bug waiting to happen. XXX BUGGO FIXME.
                root_window_id  =  root_window_id;
                event_window_id =  window_id;                                                   # Window handling the mouse-button release event.
                child_window_id =  NULL;                                                        # We'll assume specified window is a leaf.
                root_x          =  screen_col;                                                  # Mouse position on root window at time of button release.
                root_y          =  screen_row;
                event_x         =  col;                                                         # Mouse position on recipient window at time of button release.
                event_y         =  row;
                buttons         =  kab::make_mousebutton_state [ ];                             # Mouse buttons state BEFORE button press.

# trace {. "xsession: send_fake_mousebutton_press_event/YYY calling s2w::encode_send_buttonpress_xevent"; };
                command =   s2w::encode_send_buttonpress_xevent
                              {
                                send_event_to,  propagate,  event_mask,
                                timestamp,  root_window_id,  event_window_id,
                                child_window_id,  root_x,  root_y,
                                event_x,  event_y,  button, buttons
                              };

                windowsystem_to_xserver.xclient_to_sequencer.send_xrequest  command;            # Here we used to have          xclient_to_sequencer.send_xrequest  command;
                                                                                                # but to avoid race conditions we prefer nowdays to avoid bypassing xserver.
# trace {. "xsession: send_fake_mousebutton_press_event/BOT called  s2w::encode_send_buttonpress_xevent -- DONE"; };
                ();
            };
        #
        fun send_fake_mousebutton_release_xevent
            (
              { default_screen_info =>  { xscreen =>  { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
                ...
              }: Xsession
            )
            { window =>  window as { window_id, windowsystem_to_xserver, ... }: Window,         # Window handling the mouse-button click event.
              button,                                                                           # Mouse button just "clicked" down.
              point  =>  point as { row, col }                                                  # Click location in local window coordinates.
            }
            =
            {   # We need the clickpoint in both
                # local and screen coords:
                #
# trace {. sprintf "xsession: send_fake_mousebutton_release_xevent/TOP window_point = { row %d, col %d }." row col; };
                (window_point_to_screen_point  window  point)
                    ->
                    { row => screen_row,
                      col => screen_col
                    };

# trace {. sprintf "xsession: send_fake_mousebutton_release_xevent/MID screen_point = { row %d, col %d }." screen_row screen_col; };
                # For the semantics of these three fields see
                #     p27 http://mythryl.org/pub/exene/X-protocol-R6.pdf
                #
                send_event_to   =  xt::SEND_EVENT_TO_WINDOW  window_id;
                propagate       =  FALSE;
                event_mask      =  xt::EVENT_MASK 0u0;
                #
#               timestamp       =  xt::CURRENT_TIME;                                            # I had thought the X server would fill this in for us, but apparently it passes it through. :-(
                timestamp       =  bogus_current_x_timestamp ();                                # This won't sync with real X server timestamps, but I don't see a simple way to make it do so.
                                                                                                # Currently we never mix synthetic and natural X events, but this is a bug waiting to happen. XXX BUGGO FIXME.
                root_window_id  =  root_window_id;
                event_window_id =  window_id;                                                   # Window handling the mouse-button release event.
                child_window_id =  NULL;                                                        # We'll assume specified window is a leaf.
                root_x          =  screen_col;                                                  # Mouse position on root window at time of button release.
                root_y          =  screen_row;
                event_x         =  col;                                                         # Mouse position on recipient window at time of button release.
                event_y         =  row;
                buttons         =  kab::make_mousebutton_state [ button ];                      # Mouse buttons state BEFORE button release.

# trace {. "xsession: send_fake_mousebutton_release_xevent/YYY calling s2w::encode_send_buttonpress_xevent"; };
                command =   s2w::encode_send_buttonrelease_xevent
                              {
                                send_event_to,  propagate,  event_mask,
                                timestamp,  root_window_id,  event_window_id,
                                child_window_id,  root_x,  root_y,
                                event_x,  event_y,  button, buttons
                              };

                windowsystem_to_xserver.xclient_to_sequencer.send_xrequest  command;            # Here we used to have          xclient_to_sequencer.send_xrequest  command;
                                                                                                # but to avoid race conditions we prefer nowdays to avoid bypassing xserver.
# trace {. "xsession: send_fake_mousebutton_release_event/BOT called  s2w::encode_send_buttonpress_xevent -- DONE"; };
                ();
            };

        #
        fun send_fake_mouse_motion_xevent
            (
              { default_screen_info =>  { xscreen =>  { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
                ...
              }: Xsession
            )
            { window =>  window as { window_id, windowsystem_to_xserver, ... }: Window,         # Window handling the mouse-moution event.
              buttons,                                                                          # Mouse button(s) being dragged.
              point  =>  point as { row, col }                                                  # Motion location in local window coordinates.
            }
            =
            {   # We need the clickpoint in both
                # local and screen coords:
                #
# trace {. sprintf "xsession: send_fake_mouse_motion_xevent/TOP window_point = { row %d, col %d }." row col; };
                (window_point_to_screen_point  window  point)
                    ->
                    { row => screen_row,
                      col => screen_col
                    };

# trace {. sprintf "xsession: send_fake_mouse_motion_xevent/MID screen_point = { row %d, col %d }." screen_row screen_col; };
                # For the semantics of these three fields see
                #     p27 http://mythryl.org/pub/exene/X-protocol-R6.pdf
                #
                send_event_to   =  xt::SEND_EVENT_TO_WINDOW  window_id;
                propagate       =  FALSE;
                event_mask      =  xt::EVENT_MASK 0u0;
                #
#               timestamp       =  xt::CURRENT_TIME;                                            # I had thought the X server would fill this in for us, but apparently it passes it through. :-(
                timestamp       =  bogus_current_x_timestamp ();                                # This won't sync with real X server timestamps, but I don't see a simple way to make it do so.
                                                                                                # Currently we never mix synthetic and natural X events, but this is a bug waiting to happen. XXX BUGGO FIXME.
                root_window_id  =  root_window_id;
                event_window_id =  window_id;                                                   # Window handling the mouse-button release event.
                child_window_id =  NULL;                                                        # We'll assume specified window is a leaf.
                root_x          =  screen_col;                                                  # Mouse position on root window at time of button release.
                root_y          =  screen_row;
                event_x         =  col;                                                         # Mouse position on recipient window at time of button release.
                event_y         =  row;
                buttons         =  kab::make_mousebutton_state buttons;                         # Mouse buttons being dragged

# trace {. "xsession: send_fake_mouse_motion_xevent/YYY calling s2w::encode_send_motionnotify_xevent"; };
                command =   s2w::encode_send_motionnotify_xevent
                              {
                                send_event_to,  propagate,  event_mask,
                                timestamp,  root_window_id,  event_window_id,
                                child_window_id,  root_x,  root_y,
                                event_x,  event_y,  buttons
                              };

                windowsystem_to_xserver.xclient_to_sequencer.send_xrequest  command;            # Here we used to have          xclient_to_sequencer.send_xrequest  command;
                                                                                                # but to avoid race conditions we prefer nowdays to avoid bypassing xserver.
# trace {. "xsession: send_fake_mouse_motion_event/BOT called  s2w::encode_send_motionnotify_xevent -- DONE"; };
                ();
            };

        #
        fun send_fake_''mouse_enter''_xevent
            (
              { default_screen_info =>  { xscreen =>  { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
                ...
              }: Xsession
            )
            { window =>  window as { window_id, windowsystem_to_xserver, ... }: Window,         # Window handling the mouse-button click event.
              point  =>  point as { row, col }                                                  # Click location in local window coordinates.
            }
            =
            {   # We need the point in both
                # local and screen coords:
                #
# trace {. sprintf "xsession: send_fake_''mouse_enter''_xevent/TOP window_point = { row %d, col %d }." row col; };
                (window_point_to_screen_point  window  point)
                    ->
                    { row => screen_row,
                      col => screen_col
                    };

# trace {. sprintf "xsession: send_fake_''mouse_enter''_xevent/MID screen_point = { row %d, col %d }." screen_row screen_col; };
                # For the semantics of these three fields see
                #     p27 http://mythryl.org/pub/exene/X-protocol-R6.pdf
                #
                send_event_to   =  xt::SEND_EVENT_TO_WINDOW  window_id;
                propagate       =  FALSE;
                event_mask      =  xt::EVENT_MASK 0u0;
                #
#               timestamp       =  xt::CURRENT_TIME;                                            # I had thought the X server would fill this in for us, but apparently it passes it through. :-(
                timestamp       =  bogus_current_x_timestamp ();                                # This won't sync with real X server timestamps, but I don't see a simple way to make it do so.
                                                                                                # Currently we never mix synthetic and natural X events, but this is a bug waiting to happen. XXX BUGGO FIXME.
                root_window_id  =  root_window_id;
                event_window_id =  window_id;                                                   # Window handling the mouse-button release event.
                child_window_id =  NULL;                                                        # We'll assume specified window is a leaf.
                root_x          =  screen_col;                                                  # Mouse position on root window at time of button release.
                root_y          =  screen_row;
                event_x         =  col;                                                         # Mouse position on recipient window at time of button release.
                event_y         =  row;
                buttons         =  xt::MOUSEBUTTON_STATE 0u0;

# trace {. "xsession: send_fake_''mouse_enter''_xevent/YYY calling s2w::encode_send_enternotify_xevent"; };
                command =   s2w::encode_send_enternotify_xevent
                              {
                                send_event_to,  propagate,  event_mask,
                                timestamp,  root_window_id,  event_window_id,
                                child_window_id,  root_x,  root_y,
                                event_x,  event_y, buttons
                              };

                windowsystem_to_xserver.xclient_to_sequencer.send_xrequest  command;            # Here we used to have          xclient_to_sequencer.send_xrequest  command;
                                                                                                # but to avoid race conditions we prefer nowdays to avoid bypassing xserver.
# trace {. "xsession: send_fake_''mouse_enter''_xevent/BOT called  s2w::encode_send_enternotify_xevent -- DONE"; };
                ();
            };


        fun send_fake_''mouse_leave''_xevent
            (
              { default_screen_info =>  { xscreen =>  { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info,
                ...
              }: Xsession
            )
            { window =>  window as { window_id, windowsystem_to_xserver, ... }: Window,         # Window handling the mouse-button click event.
              point  =>  point as { row, col }                                                  # Click location in local window coordinates.
            }
            =
            {   # We need the point in both
                # local and screen coords:
                #
# trace {. sprintf "xsession: send_fake_''mouse_leave''_xevent/TOP window_point = { row %d, col %d }." row col; };
                (window_point_to_screen_point  window  point)
                    ->
                    { row => screen_row,
                      col => screen_col
                    };

# trace {. sprintf "xsession: send_fake_''mouse_leave''_xevent/MID screen_point = { row %d, col %d }." screen_row screen_col; };
                # For the semantics of these three fields see
                #     p27 http://mythryl.org/pub/exene/X-protocol-R6.pdf
                #
                send_event_to   =  xt::SEND_EVENT_TO_WINDOW  window_id;
                propagate       =  FALSE;
                event_mask      =  xt::EVENT_MASK 0u0;
                #
#               timestamp       =  xt::CURRENT_TIME;                                            # I had thought the X server would fill this in for us, but apparently it passes it through. :-(
                timestamp       =  bogus_current_x_timestamp ();                                # This won't sync with real X server timestamps, but I don't see a simple way to make it do so.
                                                                                                # Currently we never mix synthetic and natural X events, but this is a bug waiting to happen. XXX BUGGO FIXME.
                root_window_id  =  root_window_id;
                event_window_id =  window_id;                                                   # Window handling the mouse-button release event.
                child_window_id =  NULL;                                                        # We'll assume specified window is a leaf.
                root_x          =  screen_col;                                                  # Mouse position on root window at time of button release.
                root_y          =  screen_row;
                event_x         =  col;                                                         # Mouse position on recipient window at time of button release.
                event_y         =  row;
                buttons         =  xt::MOUSEBUTTON_STATE 0u0;

# trace {. "xsession: send_fake_''mouse_leave''_xevent/YYY calling s2w::encode_send_leavenotify_xevent"; };
                command =   s2w::encode_send_leavenotify_xevent
                              {
                                send_event_to,  propagate,  event_mask,
                                timestamp,  root_window_id,  event_window_id,  child_window_id,  root_x,  root_y,  event_x,  event_y, buttons
                              };

                windowsystem_to_xserver.xclient_to_sequencer.send_xrequest  command;            # Here we used to have          xclient_to_sequencer.send_xrequest  command;
                                                                                                # but to avoid race conditions we prefer nowdays to avoid bypassing xserver.
# trace {. "xsession: send_fake_''mouse_leave''_xevent/BOT called  s2w::encode_send_leavenotify_xevent -- DONE"; };
                ();
            };


        # Close the xsession.
        # NOTE: there are probably other things
        # that should go on here, such as notifying
        # the xbuf_to_hostwindow_xevent_router.           XXX BUGGO FIXME
        #
        fun close_xsession ({ xdisplay, ... }: Xsession )
            =
            {
# I am not at all convinced I want xsession-junk closing sockets
# -- I'd like to be able to close down and restart an xsession
# without the xserver having to know. So I'm going to plant this
# here to remind me to return to this at some point when other stuff
# is more under control:
log::fatal "close_xsession called -- xsession-junk.pkg";
                # Threads will die left and right as we shut down,
                # and scary warning messages will by default be
                # logged to stdout, so suppress that to avoid
                # spooking the user:
                #
                logger::disable  thread_deathwatch::logging;

                dy::close_xdisplay  xdisplay;
            };

        # Return the maximum request size
        # supported by the display:
        #
#       fun max_request_length ({ xdisplay=>{ max_request_length, ... }: dy::Xdisplay, ... }: Xsession )
#           =
#           max_request_length;

        # Atom operations:
        #
#       stipulate
#           #   
#           fun wrap_atom_op f ({ atom_imp, ... }: Xsession )
#                =
#                f atom_imp;
#       herein
#           #
#           make_atom      =  wrap_atom_op  ai::make_atom;
#           find_atom      =  wrap_atom_op  ai::find_atom;
#           atom_to_string =  wrap_atom_op  ai::atom_to_string;
#       end;



        fun find_font  ({ font_index, ... }: Xsession )   font_name
            =
            case (fti::find_font  font_index  font_name)
                #
                THE font => font;
                #
                NULL     => {   msg =   sprintf  "find_font unable to find font '%s' -- xsession-junk.pkg"  font_name;
                                log::fatal msg;                                 # Should not return.
                                raise exception DIE msg;                        # Should never get here.
                            };
            esac;

        #
        fun default_screen_of  (xsession as { default_screen_info, ... }: Xsession )
            =
            { xsession, screen_info => default_screen_info }: Screen;

        #
#       fun get_''gui_startup_complete''_oneshot_of_xsession  (xsession as { xsocket_to_hostwindow_router, ... }: Xsession )
#           =
#           s2t::get_''gui_startup_complete''_oneshot_of
#               #
#               xsocket_to_hostwindow_router;

        #
#       fun screens_of  (xsession as { screens, ... }: Xsession )
#           =
#           map (\\ s = { xsession, screen_info => s }: Screen)
#                screens;

        #
        fun ring_bell xsession percent
            =
            send_xrequest  xsession
                (value_to_wire::encode_bell { percent => int::min (100, int::max(-100, percent)) } );


        # Screen functions:
        #
#       color_of_screen
#           =
#            cs::get_color;
        #
        fun xsession_of_screen ({ xsession, ... }: Screen)
            =
            xsession;

        # Additions by ddeboer, May 2004.
        # Dusty deBoer, KSU CIS 705, Spring 2004.

        # Return the root window of a screen.
        # This is needed in obtaining strings from xrdb,
        # as they are stored in a property of the root window:
        #
        fun root_window_of_screen ({ screen_info => { xscreen => { root_window_id, ... }: dy::Xscreen, ... }: Screen_Info, ... }: Screen )
            =
            root_window_id;

        # End additions by ddeboer
        #
        fun size_of_screen ({ screen_info => { xscreen => { size_in_pixels, ... }: dy::Xscreen, ... }: Screen_Info, ... }: Screen )
            =
            size_in_pixels;
        #
        fun mm_size_of_screen ({ screen_info => { xscreen => { size_in_mm, ... }: dy::Xscreen, ... }: Screen_Info, ... }: Screen )
            =
            size_in_mm;
        #
        fun depth_of_screen ({ screen_info => { xscreen => { root_visual, ... }: dy::Xscreen, ... }: Screen_Info, ... }: Screen )
            =
            dy::depth_of_visual root_visual;
        #
        fun display_class_of_screen ({ screen_info => { xscreen => { root_visual, ... }: dy::Xscreen, ... }: Screen_Info, ... }: Screen )
            =
            case (dy::display_class_of_visual  root_visual)
                #
                THE c => c;
                _     => xgripe::impossible "[xsession::display_class_of_screen: bogus root visual]";
            esac;

        # Return the pen-cache and draw imps
        # for given depth on given screen:
        #
        fun per_depth_imps_for_depth ({ screen_info => { per_depth_imps, ... }: Screen_Info, ... }: Screen, given_depth)
            =
            search  per_depth_imps
            where
                fun search ((sd as { depth, ... }: Per_Depth_Imps) ! rest)
                        =>
                        if (depth == given_depth)  sd;
                        else                       search rest;
                        fi;

                    search [] =>    {   msg = "invalid depth for screen";
                                        log::fatal  msg;
                                        raise exception DIE msg;
                                    };
                end;
            end;
        #
#       fun keysym_to_keycode  ( { keymap_imp, ... }: Xsession,  keysym)
#           =
#           ki::keysym_to_keycode (keymap_imp, keysym);     

    };                                                                  # package xsession_junk
end;                                                                    # stipulate.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext