PreviousUpNext

15.4.1659  src/lib/x-kit/xclient/src/window/xevent-router-ximp.pkg

## xevent-router-ximp.pkg
#
# Replaces   src/lib/x-kit/xclient/src/window/xsocket-to-hostwindow-router-old.pkg
#
#        src/lib/x-kit/xclient/src/window/xevent-router-ximp.pkg
#        src/lib/x-kit/xclient/src/window/keymap-ximp.pkg
#
# For the big picture see the imp dataflow diagrams in
#
#     src/lib/x-kit/xclient/src/window/xclient-ximps.pkg
#
# The xsequencer_ximp is responsible for matching
# replies read from the X with requests sent
# to it.
#
# All requests to the X-server go through the xsequencer_ximp,
# as do all replies from the X-server.
#
# The xsequencer_ximp communicates on five fixed channels:
#
#   plea_mailslot       -- request messages from clients
#   from_x_mailslot     -- reply, error and event messages from the X server (via the input buffer)
#   to_x_mailslot       -- requests messages to the X server (via the output buffer)
#   xevent_mailslot     -- X-events to the X-event buffer (and thence to clients)
#   error_sink_mailslot -- errors to the error handler
#
# In addition, the xsequencer_ximp sends replies
# to clients on the reply channel that was
# bundled with the request.
#
# We maintain a pending-reply queue of requests sent
# to the X server for which replies are expected but
# not yet received.
#     We represent it using the usual two-list arrangement,
# writing new entries to the rear list while reading them
# from the front list; when the front list is empty we
# reverse the rear list and make it the new front list.

# 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 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 hx  =  hash_xid;                                    # hash_xid                                      is from   src/lib/x-kit/xclient/src/stuff/hash-xid.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 xwp =  windowsystem_to_xevent_router;               # windowsystem_to_xevent_router                 is from   src/lib/x-kit/xclient/src/window/windowsystem-to-xevent-router.pkg
    package xes =  xevent_sink;                                 # xevent_sink                                   is from   src/lib/x-kit/xclient/src/wire/xevent-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 xm  =  xt::xid_map;                                 # Map where key::Key == xt::Xid.

    #
    trace =  xtr::log_if  xtr::io_logging  0;                   # Conditionally write strings to tracing.log or whatever.
herein


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

    package   xevent_router_ximp
    : (weak)  Xevent_Router_Ximp                                # Xevent_Router_Ximp                            is from   src/lib/x-kit/xclient/src/window/xevent-router-ximp.api
    {
        Envelope_Route
          = ENVELOPE_ROUTE_END  xt::Window_Id
          | ENVELOPE_ROUTE     (xt::Window_Id, Envelope_Route)
          ;

        Window_Info
            =
            WINDOW_INFO
              {
                window_id:      xt::Window_Id,                                  # 29-bit X id for this particular window.
                route:          xwp::Envelope_Route,                            # Path needed to reach this window, starting at its hostwindow.
                parent_info:    Null_Or( Window_Info ),
                #
                children:       Ref( List(Window_Info) ),
                lock:           Ref( Bool ),
                site:           Ref( g2d::Box ),
                #
                seen_first_expose:              Ref( Bool ),                    # We set this TRUE on first EXPOSE event.
                seen_first_expose_oneshot:      Oneshot_Maildrop(Void),         # We set this      on first EXPOSE event.
                #
                xevent_sink:   (xwp::Envelope_Route, xet::x::Event) -> Void     # Where to send events headed for this window.
              };

        Xevent_Router_Ximp_State                                                                                        # Holds all nonephemeral mutable state maintained by ximp.
          =
          { wid_to_winfo:   Ref( xm::Map( Window_Info ) ),                                                              # "wid_to_winfo" == "window id to window info map"
            #
#           wid_to_pleas:   Ref( xm::Map( List(Client_Plea) ) ),                                                        # "wid_to_pleas" == "window id to window pleas map"

            wid_to_1shot:   Ref( xm::Map( Oneshot_Maildrop(Void) ) )                                                    # "wid_to_1shot" == "window id to oneshot map"
          };

        Imports   = {                                                                                                   # Ports we use which are exported by other imps.
                      xevent_router_to_keymap:                  r2k::Xevent_Router_To_Keymap,
                      window_property_xevent_sink:              xes::Xevent_Sink,                                       # 
                      selection_xevent_sink:                    xes::Xevent_Sink                                        # 
                    };

        Me_Slot = Mailslot( { imports:                          Imports,
                              me:                               Xevent_Router_Ximp_State,
                              run_gun':                         Run_Gun,
                              end_gun':                         End_Gun
                            }
                          );


        Exports   = {                                                                                                   # Ports we export for use by other imps.
                      xevent_sink:                              xes::Xevent_Sink,                                       # For xevents from xserver via inbuf, sequencer and decoder ximp.
                      windowsystem_to_xevent_router:            xwp::Windowsystem_To_Xevent_Router                              # Requests from widget/application code.
                    };

        
        Option = MICROTHREAD_NAME String;                                                                               # 

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

        # The various things we can
        # do with a given X event:
        #
        Xevent_Action
          #     
          = SEND_TO_WINDOW                        xt::Window_Id                 # Forward event to given window via all of its ancestors from hostwindow down.
          | NOTE_SITE_CHANGE_AND_SEND_TO_WINDOW  (xt::Window_Id, g2d::Box)      # Note new size+position of window, then forward event normally.
          | NOTE_WINDOW_DESTRUCTION               xt::Window_Id
          | SEND_TO_KEYMAP_IMP                                                  # This appears to be unused at present.
          | SEND_TO_WINDOW_PROPERTY_IMP
          | SEND_TO_SELECTION_IMP
          | SEND_TO_ALL_WINDOWS                                                 # So everyone hears about changes in modifier key, keyboard and pointer mappings.
          | IGNORE
          | NOTE_NEW_WINDOW
              { parent_window_id:   xt::Window_Id,
                created_window_id:  xt::Window_Id,
                box:                g2d::Box 
              }
          ;

        Xevent_Q =  Mailqueue( xet::x::Event );

        Runstate =  {                                                                                                   # These values will be statically globally visible throughout the code body for the imp.
                      me:                               Xevent_Router_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.
                      xevent_q:                         Xevent_Q                                                        # 
                    };

        Client_Q =  Mailqueue( Runstate -> Void );

        # Discard instances of an X-event that
        # are the product of SubstructureNotify,
        # instead of StructureNotify.
        #
        fun ignore_substructure_notify_xevents (window_id1, window_id2)
            =
            if (xt::same_xid (window_id1, window_id2))  SEND_TO_WINDOW window_id1;
            else                                            IGNORE;
            fi;

        # Decide what action to take for given X event.  Here
        #
        #     event_window_id
        #
        # is the window corresponding to the widget which
        # should actually handle the event, as determined
        # by the X server;  the X server algorithm is
        # described on pages 76-77 of
        #
        #     http://mythryl.org/pub/exene/X-protocol-R6.pdf
        #
        fun pick_xevent_action (xet::x::KEY_PRESS      { event_window_id, ... } ) =>  SEND_TO_WINDOW event_window_id;
            pick_xevent_action (xet::x::KEY_RELEASE    { event_window_id, ... } ) =>  SEND_TO_WINDOW event_window_id;
            pick_xevent_action (xet::x::BUTTON_PRESS   { event_window_id, ... } ) =>  SEND_TO_WINDOW event_window_id;
            pick_xevent_action (xet::x::BUTTON_RELEASE { event_window_id, ... } ) =>  SEND_TO_WINDOW event_window_id;
            pick_xevent_action (xet::x::MOTION_NOTIFY  { event_window_id, ... } ) =>  SEND_TO_WINDOW event_window_id;
            pick_xevent_action (xet::x::ENTER_NOTIFY   { event_window_id, ... } ) =>  SEND_TO_WINDOW event_window_id;
            pick_xevent_action (xet::x::LEAVE_NOTIFY   { event_window_id, ... } ) =>  SEND_TO_WINDOW event_window_id;
            pick_xevent_action (xet::x::FOCUS_IN       { event_window_id, ... } ) =>  SEND_TO_WINDOW event_window_id;
            pick_xevent_action (xet::x::FOCUS_OUT      { event_window_id, ... } ) =>  SEND_TO_WINDOW event_window_id;

#           pick_xevent_action (xet::x::KeymapNotify {, ... } ) = 
#           pick_xevent_action (xet::x::GraphicsExpose ?? 
#           pick_xevent_action (xet::x::NoExpose {, ... } ) =
#           pick_xevent_action (xet::x::MapRequest {, ... } ) =
#           pick_xevent_action (xet::x::ConfigureRequest {, ... } ) =
#           pick_xevent_action (xet::x::ResizeRequest {, ... } ) =
#           pick_xevent_action (xet::x::CirculateRequest {, ... } ) =

            pick_xevent_action (xet::x::EXPOSE { exposed_window_id, ... } ) =>  SEND_TO_WINDOW  exposed_window_id;


            pick_xevent_action (xet::x::VISIBILITY_NOTIFY { changed_window_id, ... } ) =>  SEND_TO_WINDOW  changed_window_id;

            pick_xevent_action (xet::x::CREATE_NOTIFY { parent_window_id, created_window_id, box, ... } )
                =>
                NOTE_NEW_WINDOW { parent_window_id, created_window_id, box };

            pick_xevent_action (xet::x::DESTROY_NOTIFY { event_window_id, destroyed_window_id, ... } )
                =>
                xt::same_xid (event_window_id, destroyed_window_id)
                    ##
                    ??  NOTE_WINDOW_DESTRUCTION  event_window_id        # Remove window from registry. 
                    ::  SEND_TO_WINDOW           event_window_id;       # Report to parent that child is dead. 

            pick_xevent_action (xet::x::UNMAP_NOTIFY { event_window_id, unmapped_window_id, ... } )
                =>
                ignore_substructure_notify_xevents (event_window_id, unmapped_window_id);

            pick_xevent_action (xet::x::MAP_NOTIFY { event_window_id, mapped_window_id, ... } )
                =>
                ignore_substructure_notify_xevents (event_window_id, mapped_window_id);


            pick_xevent_action (xet::x::REPARENT_NOTIFY _)
                =>
                IGNORE;

            pick_xevent_action (xet::x::CONFIGURE_NOTIFY { event_window_id, configured_window_id, box, ... } )
                =>
                case (ignore_substructure_notify_xevents (event_window_id, configured_window_id))
                    #
                    SEND_TO_WINDOW _ =>  NOTE_SITE_CHANGE_AND_SEND_TO_WINDOW (configured_window_id, box);
                    _                =>  IGNORE;
                esac;


            pick_xevent_action (xet::x::GRAVITY_NOTIFY { event_window_id, moved_window_id, ... } )
                =>
                ignore_substructure_notify_xevents (event_window_id, moved_window_id);


            pick_xevent_action (xet::x::CIRCULATE_NOTIFY { event_window_id, circulated_window_id, ... } )
                =>
                ignore_substructure_notify_xevents (event_window_id, circulated_window_id);


            pick_xevent_action (xet::x::PROPERTY_NOTIFY   _) => SEND_TO_WINDOW_PROPERTY_IMP;    # We may have other uses of PropertyNotify someday.
            pick_xevent_action (xet::x::SELECTION_CLEAR   _) => SEND_TO_SELECTION_IMP;
            pick_xevent_action (xet::x::SELECTION_REQUEST _) => SEND_TO_SELECTION_IMP;
            pick_xevent_action (xet::x::SELECTION_NOTIFY  _) => SEND_TO_SELECTION_IMP;

            pick_xevent_action (xet::x::COLORMAP_NOTIFY { window_id, ... } ) => SEND_TO_WINDOW window_id;
            pick_xevent_action (xet::x::CLIENT_MESSAGE  { window_id, ... } ) => SEND_TO_WINDOW window_id;

            pick_xevent_action  xet::x::MODIFIER_MAPPING_NOTIFY     => SEND_TO_ALL_WINDOWS;
            pick_xevent_action (xet::x::KEYBOARD_MAPPING_NOTIFY _)  => SEND_TO_ALL_WINDOWS;
            pick_xevent_action  xet::x::POINTER_MAPPING_NOTIFY      => SEND_TO_ALL_WINDOWS;

            pick_xevent_action e => {   log::fatal (string::cat [ "[xsocket-to-topwin: unexpected ", xevent_to_string::xevent_name e, " event]\n"]);
                                        IGNORE;
                                    };
        end;

        # Define a tracelogging version of
        #
        #     pick_xevent_action
        #
        stipulate
            #
            fun xevent_action_to_string (SEND_TO_WINDOW w)
                    =>
                    ("SEND_TO_WINDOW(" + xt::xid_to_string w + ")");

                xevent_action_to_string (NOTE_SITE_CHANGE_AND_SEND_TO_WINDOW (w,_))
                    =>
                    ("NOTE_SITE_CHANGE_AND_SEND_TO_WINDOW(" + xt::xid_to_string w + ")");

                xevent_action_to_string (NOTE_NEW_WINDOW { parent_window_id, created_window_id, box } )
                    =>
                    string::cat
                      [
                        "NOTE_NEW_WINDOW { parent=",  xt::xid_to_string  parent_window_id,
                              ", new_window=",  xt::xid_to_string created_window_id,
                        "}"
                      ];

                xevent_action_to_string (NOTE_WINDOW_DESTRUCTION w) => ("NOTE_WINDOW_DESTRUCTION(" + xt::xid_to_string w + ")");
                xevent_action_to_string SEND_TO_KEYMAP_IMP          => "SEND_TO_KEYMAP_IMP";
                xevent_action_to_string SEND_TO_WINDOW_PROPERTY_IMP => "SEND_TO_WINDOW_PROPERTY_IMP";
                xevent_action_to_string SEND_TO_SELECTION_IMP       => "SEND_TO_SELECTION_IMP";
                xevent_action_to_string SEND_TO_ALL_WINDOWS         => "SEND_TO_ALL_WINDOWS";
                xevent_action_to_string IGNORE                      => "IGNORE";
            end;

        herein
            #
            pick_xevent_action
                =
                \\ xevent
                    =
                    {   xevent_action =  pick_xevent_action  xevent;

                        trace {.
                            #
                            cat [ "xsocket_to_hostwindow_router: ", xevent_to_string::xevent_name  xevent,
                                  " => ", xevent_action_to_string xevent_action
                                ];
                        };

                        xevent_action;
                    };
        end;
    #  -DEBUG 


#       fun set_window_subtree_locks_to                                                                                 # Commented out 2014-06-28 because it is never referenced.
#               (bool: Bool)    
#           =
#           set
#           where
#               fun set (WINDOW_INFO { lock, children, ... } )
#                   =
#                   {   lock := bool;
#                       set_list *children;
#                   }
#
#               also
#               fun set_list (wd ! r)
#                       =>
#                       {   set wd;
#                           set_list r;
#                       };
#
#                   set_list []
#                       =>
#                       ();
#               end;
#           end;


        fun run ( client_q:                             Client_Q,                                                       # Requests from x-widgets and such
                  gui_startup_complete_oneshot,
                  #
                  runstate as
                  {                                                                                                     # These values will be statically globally visible throughout the code body for the imp.
                    me:                                 Xevent_Router_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.
                    xevent_q:                           Xevent_Q                                                        # 
                  }
                )
            =
            loop ()
            where
                fun loop ()                                                                                             # Outer loop for the imp.
                    =
                    {   do_one_mailop' to [
                            #
                            (end_gun'                       ==>  shut_down_xevent_to_window_imp'),
                            (take_from_mailqueue' client_q  ==>  do_client_plea),
                            (take_from_mailqueue' xevent_q  ==>  do_xevent)
                        ];

                        loop ();
                    }   
                    where

                        fun do_client_plea thunk
                            =
                            thunk runstate;

                        fun shut_down_xevent_to_window_imp' ()
                            =
                            thread_exit { success => TRUE };                                                            # Will not return.      
                        #

                        fun get_winfo  window_id
                            =
{
# printf "get_winfo -- xevent-router-ximp.pkg\n";
                            case (xm::get (*me.wid_to_winfo, window_id))
                                #
                                THE winfo =>    {
# printf "get_winfo found entry!  -- xevent-router-ximp.pkg\n";
                                                    winfo;
                                                };
                                NULL      =>    {   log::fatal ("window_id not found -- do_plea (plea::GET_WINDOW_SITE in xevent-router-ximp.pkg");
                                                    raise exception DIE "";                                             # Should not get here.
                                                };
                            esac;
};


                        #
                        fun note_new_subwindow (parent_window_id, child_window_id, box)
                            =
                            {   parent_info =  get_winfo  parent_window_id;
                                #
                                parent_info ->  WINDOW_INFO { route, xevent_sink, children, lock, ... };
                                #
                                fun extend_route (xwp::ENVELOPE_ROUTE_END window_id)      =>  xwp::ENVELOPE_ROUTE (window_id, xwp::ENVELOPE_ROUTE_END child_window_id);
                                    extend_route (xwp::ENVELOPE_ROUTE (window_id, route)) =>  xwp::ENVELOPE_ROUTE (window_id, extend_route route);
                                end;

                                child_route =  extend_route  route;


                                child_info
                                    =
                                    WINDOW_INFO
                                      {
                                        window_id   =>  child_window_id,
                                        route       =>  child_route,
                                        site        =>  REF box,
                                        parent_info =>  THE parent_info,
                                        children    =>  REF [],
                                        lock        =>  REF *lock,
                                        #
                                        xevent_sink,
                                        #
                                        seen_first_expose         => REF( FALSE ),
                                        seen_first_expose_oneshot => (make_oneshot_maildrop ())
                                      };

                                children :=  child_info ! *children;

                                me.wid_to_winfo :=  xm::set (*me.wid_to_winfo, child_window_id, child_info);
                            };

                        #
                        fun note_site_change (window_id, box)
                            =
                            {   (get_winfo window_id) ->  WINDOW_INFO { site, ... };
                                #
                                site := box;
                            };

                        #
                        fun route_xevent_per_window_info (xevent, WINDOW_INFO { route, xevent_sink, ... } )
                            = 
                            xevent_sink (route, xevent);

                        #
                        fun route_xevent_to_window_id (xevent, window_id)
                            =
{
# printf "route_xevent_to_window_idAAA -- xevent-router-ximp.pkg\n";
                            route_xevent_per_window_info  (xevent,  get_winfo window_id);
};

                        #
                        fun do_xevent  xevent
                            =
{
# printf "do_xevent/AAA -- xevent-router-ximp.pkg\n";
                            case (pick_xevent_action  xevent)
                                #
                                SEND_TO_WINDOW  window_id
                                    =>
{
# printf "do_xevent/SEND_TO_WINDOW  -- xevent-router-ximp.pkg\n";

                                    route_xevent_to_window_id (xevent, window_id);
};

                                NOTE_SITE_CHANGE_AND_SEND_TO_WINDOW (window_id, box)
                                    =>
                                    {   note_site_change (window_id, box);                      # Window has changed size and/or position.
                                        #
                                        route_xevent_to_window_id (xevent, window_id);
                                    };

                                NOTE_NEW_WINDOW { parent_window_id, created_window_id, box }
                                    =>
                                    {   note_new_subwindow (parent_window_id, created_window_id, box);
                                        #
                                        route_xevent_to_window_id (xevent, parent_window_id);
                                    };

                                NOTE_WINDOW_DESTRUCTION  window_id
                                    =>
                                    case (xm::get_and_drop (*me.wid_to_winfo, window_id))
                                        #
                                        (new_wid_to_winfo, THE (window_info as WINDOW_INFO { parent_info => THE (WINDOW_INFO { children, ... } ), ... } ))
                                            =>
                                            {   me.wid_to_winfo :=  new_wid_to_winfo;
                                                #
                                                children :=   remove_child  *children;

                                                route_xevent_per_window_info (xevent, window_info);
                                            }
                                            where
                                                fun remove_child ((window_info' as WINDOW_INFO { window_id => window_id', ... } ) ! rest)
                                                        =>
                                                        if (xt::same_xid (window_id', window_id))                               rest  ;
                                                        else                                      (window_info' ! (remove_child rest));
                                                        fi;

                                                    remove_child []
                                                        =>
                                                        {   log::fatal ("Missing child -- do_xevent/NOTE_WINDOW_DESTRUCTION in xevent-router-ximp.pkg");
                                                            raise exception DIE "";     # Shouldn't get here.
                                                        };
                                                end;
                                            end;


                                        (new_wid_to_winfo, THE window_info)
                                            =>
                                            {   me.wid_to_winfo :=  new_wid_to_winfo;
                                                #
                                                route_xevent_per_window_info (xevent, window_info);
                                            };

                                        (new_wid_to_winfo, NULL)
                                            =>
                                            {   log::fatal ("Missing window -- do_xevent/NOTE_WINDOW_DESTRUCTION in xevent-router-ximp.pkg");
                                                raise exception DIE ""; # Shouldn't get here.
                                            };
                                    esac;

                                SEND_TO_KEYMAP_IMP
                                    =>
                                    {   log::fatal ("Unexpected SEND_TO_KEYMAP_IMP do_xevent in xevent-router-ximp.pkg]");
                                        raise exception DIE "";
                                    };

                                SEND_TO_WINDOW_PROPERTY_IMP  =>  imports.window_property_xevent_sink.put_value  xevent;
                                SEND_TO_SELECTION_IMP        =>  imports.selection_xevent_sink.put_value        xevent;

                                IGNORE => ();

                                SEND_TO_ALL_WINDOWS
                                    =>
                                    apply' (xm::vals_list  *me.wid_to_winfo)
                                           {. route_xevent_per_window_info (xevent, #window_info); };
                            esac;                                                                                       # fun do_xevent
};
                    end;                                                                                                # fun loop
            end;                                                                                                        # fun run
        
        fun startup   (reply_oneshot:  Oneshot_Maildrop( (Me_Slot, Exports) ))   ()                                     # Root fn of imp microthread.  Note currying.
            =
            {   me_slot =  make_mailslot  ()    :  Me_Slot;
                #
                xevent_sink =  { put_value };

                windowsystem_to_xevent_router
                  =
                  { note_new_hostwindow,
                    get_window_site,
                    given_window_id_pass_site,
                    get_''seen_first_expose''_oneshot_of,
                    get_''gui_startup_complete''_oneshot_of
                  };


                to             =  make_replyqueue();

                put_in_oneshot (reply_oneshot, (me_slot, { xevent_sink, windowsystem_to_xevent_router }));                      # Return value from xevent_to_window_egg'().

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

                block_until_mailop_fires  run_gun';                                                                     # Wait for the starting gun.

                run (client_q, gui_startup_complete_oneshot, { me, xevent_q, imports, to, end_gun' });                  # Will not return.
            }
            where
                client_q =  make_mailqueue (get_current_microthread())  :  Client_Q;
                xevent_q =  make_mailqueue (get_current_microthread())  :  Xevent_Q;

                gui_startup_complete_oneshot
                    =   
                    make_oneshot_maildrop ():  Oneshot_Maildrop( Void );
                        #
                        # This maildrop exists to give application threads
                        # something to wait on before presuming that the
                        # GUI widgettree windows, threads etc are ready for action.
                        #
                        # Currently we set this when we first
                        # get an EXPOSE X event from the X server.              
                        #
                        # ===============
                        # XXX SUCKO FIXME  I'm hoping we can eliminate this with the new startup protocol. --CrT 2013-08-11
                        # ===============

                fun note_new_hostwindow                                                                                 # PUBLIC.
                      (
                        window_id:      xt::Window_Id,
                        window_site:    g2d::Window_Site,
                        xevent_sink:    (xwp::Envelope_Route, xet::x::Event) -> Void
                      )
                    =
                    put_in_mailqueue (client_q,
                            #
                            \\ ({ me, imports, ... }: Runstate)
                                =
                                {
# PLEA_NOTE_NEW_HOSTWINDOW arg
#                       fun do_plea (PLEA_NOTE_NEW_HOSTWINDOW  (window_id, window_site, xevent_sink))                   # Log a new top-level window.
#                               =>
#                               {
# I have the following in the oldworld, I'm not
# implementing that here partly out of laziness
# but mostly out of revulsion -- there must be
# something less awful.
#
#                                       # Handle any prematurely-registered oneshot.
#                                       # I'm not sure a hostwindow will ever get an
#                                       # EXPOSE event, so this may be pointless:
#                                       #
#                                       oneshot =   {   oneshot =  get_from_oneshot_map  window_id;
#                                                       drop_from_oneshot_map  window_id;
#                                                       THE oneshot;
#                                                   }   
#                                                   except
#                                                       lib_base::NOT_FOUND
#                                                           =
#                                                           NULL;

                                    me.wid_to_winfo
                                        :=
                                        xm::set (
                                            *me.wid_to_winfo,
                                            window_id,
                                            WINDOW_INFO
                                              {
                                                window_id,
                                                xevent_sink,
                                                route       =>  xwp::ENVELOPE_ROUTE_END  window_id,
                                                parent_info =>  NULL,
                                                #
                                                children    =>  REF [],
                                                lock        =>  REF FALSE,
                                                site        =>  REF (g2d::site_to_box window_site),
                                                #
                                                seen_first_expose         => REF( FALSE ),
                                                seen_first_expose_oneshot => (make_oneshot_maildrop ())
                                              }
                                          );
                                }

                    );

                fun get_winfo
                      (
                        me:             Xevent_Router_Ximp_State,
                        window_id
                      )
                    =
{
printf "get_winfo -- xevent-router-ximp.pkg\n";
                    case (xm::get (*me.wid_to_winfo, window_id))
                        #
                        THE winfo =>    {
printf "get_winfo found entry!  -- xevent-router-ximp.pkg\n";
                                            winfo;
                                        };
                        NULL      =>    {   log::fatal ("window_id not found -- do_plea (plea::GET_WINDOW_SITE in xevent-router-ximp.pkg");
                                            raise exception DIE "";                                             # Should not get here.
                                        };
                    esac;
};

                fun get_''seen_first_expose''_oneshot_of  (window_id: xt::Window_Id)
                    =
                    {   reply_oneshot = make_oneshot_maildrop ()
                                      :      Oneshot_Maildrop( Oneshot_Maildrop(Void) );
                        #
                        put_in_mailqueue (client_q,
                            #
                            \\ ({ me, imports, ... }: Runstate)
                                =
                                {   (get_winfo (me, window_id)) ->  WINDOW_INFO { seen_first_expose_oneshot, ... };
                                    #
                                    put_in_oneshot (reply_oneshot, seen_first_expose_oneshot);
                                }
                        );

                        get_from_oneshot  reply_oneshot;
                    };

                fun get_''gui_startup_complete''_oneshot_of  ()
                    =
                    {   reply_oneshot = make_oneshot_maildrop ()
                                      :      Oneshot_Maildrop( Oneshot_Maildrop(Void) );
                        #
                        put_in_mailqueue (client_q,
                            #
                            \\ ({ me, imports, ... }: Runstate)
                                =
                                put_in_oneshot (reply_oneshot, gui_startup_complete_oneshot)
                        );

                        get_from_oneshot  reply_oneshot;
                    };



                fun get_window_site  (window_id: xt::Window_Id)                                                         # PUBLIC.
                    =
                    {   reply_oneshot = make_oneshot_maildrop ()
                                      :      Oneshot_Maildrop( g2d::Box );
                        #
                        put_in_mailqueue (client_q,
                            #
                            \\ ({ me, imports, ... }: Runstate)
                                =
                                {   (get_winfo (me, window_id)) ->  WINDOW_INFO { site, ... };
                                    #
                                    put_in_oneshot (reply_oneshot,  *site);
                                }
                        );

                        get_from_oneshot  reply_oneshot;
                    };

                fun given_window_id_pass_site                                                                           # PUBLIC.
                        (window_id:     xt::Window_Id)
                        (replyqueue:    Replyqueue)
                        (reply_handler: g2d::Box -> Void)
                    =
                    {   reply_oneshot =  make_oneshot_maildrop()
                                      :       Oneshot_Maildrop( g2d::Box );
                        #
                        put_in_mailqueue  (client_q,
                            #
                            \\ ({ me, imports, ... }: Runstate)
                                =
                                {   (get_winfo (me, window_id)) ->  WINDOW_INFO { site, ... };
                                    #
                                    put_in_oneshot (reply_oneshot,  *site);
                                }
                        );

                        put_in_replyqueue (replyqueue, (get_from_oneshot' reply_oneshot) ==> reply_handler);
                    };


                #
                fun put_value (xevent: xet::x::Event)                                                                   # PUBLIC.
                    =   
                    put_in_mailqueue  (xevent_q, xevent);
            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.
        #
        fun make_xevent_router_egg (options: List(Option))                                                              # PUBLIC. PHASE 1: Construct our state and initialize from 'options'.
            =
            {   (process_options (options, { name => "tmp" }))
                    ->
                    { name };
        
                me =  { wid_to_winfo =>  REF xm::empty: Ref (xm::Map( Window_Info ) ),                                  # "wid_to_winfo" == "window id to window info map"
                        #                       
#                       wid_to_pleas =>  REF xm::empty: Ref (xm::Map( List(Client_Plea) ) ),                            # "wid_to_pleas" == "window id to window pleas map"

                        wid_to_1shot =>  REF xm::empty: Ref (xm::Map( Oneshot_Maildrop(Void) ) )                        # "wid_to_1shot" == "window id to oneshot map"
                      };

                \\ () = {   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' });
                                };

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




Comments and suggestions to: bugs@mythryl.org

PreviousUpNext