PreviousUpNext

15.4.1660  src/lib/x-kit/xclient/src/window/xevent-to-widget-ximp.pkg

## xevent-to-widget-ximp.pkg
#
# For each toplevel window, which is to say
# at the root of each widget tree, we need
# a thread which accepts xevents from
#
#     src/lib/x-kit/xclient/src/window/xsocket-to-hostwindow-router-old.pkg
#
# and passes them them on down the widgettree.
#
# That's our job here.
#
# For the big picture see the diagram in
#     src/lib/x-kit/xclient/src/window/xclient-ximps.pkg

# 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 xet =  xevent_types;                                                # xevent_types                          is from   src/lib/x-kit/xclient/src/wire/xevent-types.pkg
    package kb  =  keys_and_buttons;                                            # keys_and_buttons                      is from   src/lib/x-kit/xclient/src/wire/keys-and-buttons.pkg
    package xtr =  xlogger;                                                     # xlogger                               is from   src/lib/x-kit/xclient/src/stuff/xlogger.pkg
    #
    package dy  =  display;                                                     # display                               is from   src/lib/x-kit/xclient/src/wire/display.pkg
    package di  =  xserver_ximp;                                                # xserver_ximp                          is from   src/lib/x-kit/xclient/src/window/xserver-ximp.pkg
    package w2x =  windowsystem_to_xserver;                                     # windowsystem_to_xserver               is from   src/lib/x-kit/xclient/src/window/windowsystem-to-xserver.pkg
#   package dt  =  draw_types;                                                  # draw_types                            is from   src/lib/x-kit/xclient/src/window/draw-types.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 sn  =  xsession_junk;                                               # xsession_junk                         is from   src/lib/x-kit/xclient/src/window/xsession-junk.pkg
    package s2t =  xevent_router_ximp;                                          # xevent_router_ximp                    is from   src/lib/x-kit/xclient/src/window/xevent-router-ximp.pkg
    package x2w =  windowsystem_to_xevent_router;                               # windowsystem_to_xevent_router         is from   src/lib/x-kit/xclient/src/window/windowsystem-to-xevent-router.pkg
    package wc  =  widget_cable;                                                # widget_cable                          is from   src/lib/x-kit/xclient/src/window/widget-cable.pkg
herein


    package   xevent_to_widget_ximp
    : (weak)  Xevent_To_Widget_Ximp                                             # Xevent_To_Widget_Ximp                 is from   src/lib/x-kit/xclient/src/window/xevent-to-widget-ximp.api
    {
        trace =  xtr::log_if  xtr::hostwindow_to_widget_router_tracing  0;      # Conditionally write strings to tracing.log or whatever.

        fun foo () = ();

        # The top-level window (usually a shell widget)
        # should never pass on CO message                                       # "CO" == "command out"
        #
        fun make_co_thread  co_event
            =
            make_thread "widget-cable root-end CO eater" {.
                #
                block_until_mailop_fires  co_event;

                xgripe::impossible("[widgetcable-rootend: unexpected CO message]");
            };

        fun make_router
              ( { xevent_router_to_keymap, ... }: sn::Xsession,
                xevent_in',
                drawimp_mappedstate_slot,
                top_window
              )
            =
            {   make_descendant_window
                    =
                    {   top_window ->   { screen, per_depth_imps, windowsystem_to_xserver, ... }: sn::Window;
                        #
                        \\ window_id
                            =
                            { window_id, screen, per_depth_imps, windowsystem_to_xserver, subwindow_or_view => NULL }: sn::Window;
                    };

                (wc::make_widget_cable ())
                    ->
                    { kidplug, momplug };
                    

                my (route_other_envelope', route_keyboard_envelope', route_mouse_envelope')
                    =
                    {   momplug ->  wc::MOMPLUG { other_sink, keyboard_sink, mouse_sink, from_kid' };
                        #
                        make_co_thread from_kid';

                        (other_sink, keyboard_sink, mouse_sink);
                    };

                keycode_to_keysym =  xevent_router_to_keymap.keycode_to_keysym;

                stipulate

                    seqn = REF 0;

                herein

                    fun stuff_envelope (route, contents)
                        =
                        {   n = *seqn;

                            seqn := n+1;

                            wc::ENVELOPE { route, seqn=>n, contents };
                        };
                end;

                # Create mailslot to pass client messages
                # to the application.
                #
                # This appears is a 2005 dusty deboer hack described
                # in the "Library: Deletion Events" section of
                #
                #     http://people.cis.ksu.edu/~ddeboer/eXene.html
                #
                # Receipt of (any) CLIENT_MESSAGE X event is signaled
                # (see fun route_xevent below) via this slot
                # and can be waited on via HOSTWINDOW.delete_slot
                # -- see delete_mailop in   src/lib/x-kit/widget/old/basic/hostwindow.api
                #
                # We never send a CLIENT_MESSAGE, nor does any existing
                # code reference the delete_mailop.  However, the window
                # manager 
                #
                wm_window_delete_slot =   make_mailslot ();


                fun do_key (make_msg, key_event)
                    =
                    route_keyboard_envelope' (make_msg (keycode_to_keysym key_event));


                fun do_button_press (path, info:  xet::Button_Xevtinfo)
                    =
                    {   info ->  { mouse_button, event_point, root_point, timestamp, mousebuttons_state, ... };

                        mail =  if (kb::no_mousebuttons_set  mousebuttons_state)
                                    #
                                    wc::MOUSE_FIRST_DOWN
                                      {
                                        mouse_button,
                                        window_point => event_point,
                                        screen_point => root_point,
                                        timestamp
                                      };
                                else
                                    wc::MOUSE_DOWN
                                      {
                                        mouse_button,
                                        window_point => event_point,
                                        screen_point => root_point,
                                          #  invert button so that the state is post-transition 
                                        state => kb::invert_button_in_mousebutton_state (mousebuttons_state, mouse_button),
                                        timestamp
                                      };
                                fi;

                          route_mouse_envelope' (stuff_envelope (path, mail));
                    };

                fun do_button_release (path, info:  xet::Button_Xevtinfo)
                    =
                    route_mouse_envelope' (stuff_envelope (path, msg))
                    where 
                        info ->   { mouse_button, event_point, root_point, timestamp, mousebuttons_state, ... };

                        state =  kb::invert_button_in_mousebutton_state (mousebuttons_state, mouse_button);

                        msg = if (kb::no_mousebuttons_set  state)
                                  #
                                  wc::MOUSE_LAST_UP
                                      {
                                        mouse_button,
                                        window_point => event_point,
                                        screen_point => root_point,
                                        timestamp
                                      };
                              else
                                  wc::MOUSE_UP
                                      {
                                        mouse_button,
                                        window_point => event_point,
                                        screen_point => root_point,
                                        state,
                                        timestamp
                                      };
                              fi;
                    end;


                # An always-ready mailop producing void:
                #
                always_void
                    =
                    always' ();


                fun do_config_sync (path, config_msg)
                    =
                    always_void
                        ==>
                       {.   block_until_mailop_fires (route_mouse_envelope'     (stuff_envelope (path, wc::MOUSE_CONFIG_SYNC)));
                            block_until_mailop_fires (route_keyboard_envelope'  (stuff_envelope (path, wc::KEY_CONFIG_SYNC)));
                            block_until_mailop_fires (route_other_envelope'     (stuff_envelope (path, config_msg)));
                        };

                fun route_xevent (path, xet::x::KEY_PRESS arg)
                        =>
                        {
                            do_key (\\ x = stuff_envelope (path, wc::KEY_PRESS x), arg);
                        };

                    route_xevent (path, xet::x::KEY_RELEASE arg)
                        =>
                        {
                            do_key (\\ x = stuff_envelope (path, wc::KEY_RELEASE x), arg);
                        };

                    route_xevent (path, xet::x::BUTTON_PRESS   arg)
                        =>
                        {
                            do_button_press    (path, arg);
                        };

                    route_xevent (path, xet::x::BUTTON_RELEASE arg)
                        =>
                        {
                            do_button_release  (path, arg);
                        };

                    route_xevent (path, xet::x::MOTION_NOTIFY { event_point, root_point, timestamp, ... } )
                        =>
                        route_mouse_envelope' (stuff_envelope (path, wc::MOUSE_MOTION { window_point=>event_point, screen_point=>root_point, timestamp } ));

                    route_xevent (path, xet::x::ENTER_NOTIFY { event_point, root_point, timestamp, ... } )
                        =>
                        route_mouse_envelope' (stuff_envelope (path, wc::MOUSE_ENTER { window_point=>event_point, screen_point=>root_point, timestamp } ));

                    route_xevent (path, xet::x::LEAVE_NOTIFY { event_point, root_point, timestamp, ... } )
                        =>
                        route_mouse_envelope' (stuff_envelope (path, wc::MOUSE_LEAVE { window_point=>event_point, screen_point=>root_point, timestamp } ));

          /*******
                  | route_xevent (_, xet::x::FOCUS_IN {... } ) = ()
                  | route_xevent (_, xet::x::FOCUS_OUT {... } ) = ()
                  | route_xevent (_, xet::x::KEYMAP_NOTIFY {... } ) = ()
          ******/

                    route_xevent (path, xet::x::EXPOSE { boxes, ... } )
                        =>
                        {
trace {. "route_xevent:  Handling EXPOSE"; };
                            route_other_envelope' (stuff_envelope (path, wc::ETC_REDRAW boxes));
                        };

          /*******
                  | route_xevent (_, xet::x::GRAPHICS_EXPOSE {... } ) = ()
                  | route_xevent (_, xet::x::NO_EXPOSE {... } ) = ()
                  | route_xevent (_, xet::x::VISIBILITY_NOTIFY _) = ()
          ******/

                    route_xevent (path, xet::x::CREATE_NOTIFY { parent_window_id, created_window_id, ... } )
                        =>
                        {
trace {. "route_xevent:  Handling CREATE_NOTIFY"; };
                            do_config_sync (path, wc::ETC_CHILD_BIRTH (make_descendant_window  created_window_id));
                        };

                    route_xevent (path, xet::x::DESTROY_NOTIFY { destroyed_window_id, event_window_id, ... } )
                        =>
                        destroyed_window_id == event_window_id
                            ##
                            ??   route_other_envelope' (stuff_envelope (path, wc::ETC_OWN_DEATH))
                            ::   do_config_sync (path, wc::ETC_CHILD_DEATH (make_descendant_window  destroyed_window_id));

                    route_xevent (x2w::ENVELOPE_ROUTE_END _, xet::x::UNMAP_NOTIFY _)
                        =>
                        always_void
                            ==> 
                            {.  put_in_mailslot (drawimp_mappedstate_slot, w2x::s::HOSTWINDOW_IS_NOW_UNMAPPED);  };

                    route_xevent (_, xet::x::UNMAP_NOTIFY _)
                        =>
                        always_void;

                    route_xevent (x2w::ENVELOPE_ROUTE_END _, xet::x::MAP_NOTIFY _)
                        =>
                        always_void
                            ==>
                            {.   put_in_mailslot  (drawimp_mappedstate_slot,  w2x::s::HOSTWINDOW_IS_NOW_MAPPED);   };

                    route_xevent (_, xet::x::MAP_NOTIFY _)
                        =>
                        {
trace {. "route_xevent:  'Handling' MAP_NOTIFY via always_void"; };
                            always_void;
                        };

          /*******
                  | route_xevent (_, xet::x::MAP_REQUEST {... } ) = ()
                  | route_xevent (_, xet::x::REPARENT_NOTIFY {... } ) = ()
          ******/

                  route_xevent (path, xet::x::CONFIGURE_NOTIFY { box, ... } )
                      =>
                      route_other_envelope' (stuff_envelope (path, wc::ETC_RESIZE box));

          /*******
                  | route_xevent (_, xet::x::ConfigureRequest {... } ) = ()
                  | route_xevent (_, xet::x::GravityNotify {... } ) = ()
                  | route_xevent (_, xet::x::ResizeRequest {... } ) = ()
                  | route_xevent (_, xet::x::CirculateNotify {... } ) = ()
                  | route_xevent (_, xet::x::CirculateRequest {... } ) = ()
                  | route_xevent (_, xet::x::PropertyNotify {... } ) = ()
                  | route_xevent (_, xet::x::SelectionClear {... } ) = ()
                  | route_xevent (_, xet::x::SelectionRequest {... } ) = ()
                  | route_xevent (_, xet::x::SelectionNotify {... } ) = ()
                  | route_xevent (_, xet::x::ColormapNotify {... } ) = ()
          ******/
          /****** modification, ddeboer, Jul 2004: route this event when delete. 
          from ..protocol/xevent-types.pkg:
          ... CLIENT_MESSAGE_XEVENT of {
                  window:  window_id,        
                  type:  atom,         the type of the message
                  value:  raw_data        the message value
                }
          */

                   route_xevent (_, xet::x::CLIENT_MESSAGE { window_id, type, ... } )
                       => 
                       always_void
                           ==>
                          {.   put_in_mailslot (wm_window_delete_slot, ());   };
                                #
                                # In principle we might here have received
                                # any of the following window manager messages:
                                #
                                #     WM_ACCEPT_FOCUS  -- See p33            of http://mythryl.org/pub/exene/icccm.pdf
                                #     WM_DELETE_WINDOW -- See p43 (S4.2.8.1) of http://mythryl.org/pub/exene/icccm.pdf
                                #     WM_SAVE_YOURSELF -- See p61            of http://mythryl.org/pub/exene/icccm.pdf (Obsolete -- use newer session management support.)
                                #
                                # However, we have only registered support for
                                # WM_DELETE_WINDOW so at present we presume
                                # that is what we have, without even checking.
                                # 
                                # This is a 2005 dusty deboer hack described in
                                #
                                #     http://people.cis.ksu.edu/~ddeboer/eXene.html
                                #
                                # When the user clicks on our windowframe close button,
                                # the window manager sends us a WM_DELETE_WINDOW X ClientEvent.
                                #
                                # It does this because we advertised support for the WM_DELETE_WINDOW
                                # ICCCM protocol in the set_protocols() fn in
                                #
                                #     src/lib/x-kit/widget/old/basic/hostwindow.pkg
                                #
                                # -- otherwise it would just summarily kill our X window
                                # and X socket connection.
                                #
                                # The window manager sends us WM_DELETE_WINDOW messages
                                # when the user clicks on the windowframe close button.
                                #
                                # WM_DELETE_WINDOW messages from the window manager via the
                                #     delete_mailop
                                # in
                                #     src/lib/x-kit/widget/old/basic/hostwindow.api
                                #
                                # No existing code sends a CLIENT_MESSAGE,
                                # nor does any existing code reference delete_mailop.

          # * end mod ***

                   route_xevent (_, event)
                       =>
                       always_void
                           ==>  
                          {.   trace {. cat [ "[hostwindow_to_widget_router::route_xevent: unexpected event ", xevent_to_string::xevent_name event, "]" ];  };
                           };

                end;                    # fun route_xevent

          #  +DEBUG 
                fun debug_router (result as (_, xevent))
                    = 
                    {   trace  {. cat [ "topwin2widget: get ", xevent_to_string::xevent_name xevent ];  };

                        result;
                    };
          #  -DEBUG 
                fun router ([], [])
                        =>
                        router ([debug_router  (block_until_mailop_fires  xevent_in')], []);

                    router ([], l)
                        =>
                        router (reverse l, []);

                    router (front as (msg_out ! r), rear)
                        =>
                        do_one_mailop [
                            xevent_in'
                                ==>
                                (\\ result
                                    =
                                    router (front, (debug_router result) ! rear)),

                            route_xevent msg_out
                                ==>
                               {.  router (r, rear);  }
                        ];
                end;

                ( kidplug,
                  (\\ pending = router (pending, [])),
                  wm_window_delete_slot
                );
          };                                                    # fun make_router 


        # Create the X-event-router imp and draw_imp
        # for a top-level window, returning the
        # kidplug and hostwindow.
        #
        # This function is called (only) from
        #
        #     make_simple_top_window
        #     make_simple_popup_window
        #     make_transient_window
        # in
        #     src/lib/x-kit/xclient/src/window/window-old.pkg
        #
#       fun make_hostwindow_to_widget_router
#           (
#               screen          as   { xsession,           ... }: sn::Screen,
#             per_depth_imps    as   { windowsystem_to_xserver,  ... }: sn::Per_Depth_Imps,
#             window_id,
#               site
#           )
#           =
#           {   xsession ->  { xdisplay as { xsocket, ... }: dy::Xdisplay, xsocket_to_hostwindow_router, ... }: sn::Xsession;
#               #
#               drawimp_mappedstate_slot
#                   =
#                   make_mailslot ();

# # trace {. "XYZZY make_hostwindow_to_widget_router: Doing make_draw_imp"; };
#               to_hostwindow_drawimp
#                   =
#                   di::make_draw_imp
#                         (
#                           take_from_mailslot'  drawimp_mappedstate_slot,
#                           pen_cache,  
# #                         =========   XXXX BUGGO FIXME sharing pen_caches means we really do need mutual exclusion
#                           xsocket
#                         );
# # trace {. "XYZZY make_hostwindow_to_widget_router: Done  make_draw_imp"; };

#               xevent_in'                              # We receive X events via this mailop.
#                   =
#                   s2t::note_new_hostwindow
#                     (
#                         xsocket_to_hostwindow_router,
#                       window_id,
#                       site
#                     );

#               top_window
#                   =
#                   { window_id, screen, per_depth_imps, to_hostwindow_drawimp }: sn::Window;

#               my (kidplug, router, wm_window_delete_slot)
#                   =
#                   make_router (xsession, xevent_in', drawimp_mappedstate_slot, top_window);

#               fun init_router ()
#                   =
#                   {
#                       fun loop buf
#                           =
#                           case (block_until_mailop_fires  xevent_in')
#                               #
#                               arg as (_, xet::x::EXPOSE _)
#                                   =>
#                                   {
#                                                                                           /* DEBUG */ # trace {. "init_router: ExposeEvt"; };
#                                       put_in_mailslot  (drawimp_mappedstate_slot,  di::s::FIRST_EXPOSE);
#                                                                                           /* DEBUG */ # trace {. "init_router: DM_FirstExpose sent"; };
#                                       (arg ! buf);
#                                   };

#                               arg => loop (arg ! buf);
#                           esac;

#                                                                                           /* DEBUG */ # trace {. cat ["init_router: window_id = ", xt::xid_to_string window_id]; };
#                         router (reverse (loop []));
#                                                                                           /* DEBUG */ # trace {. "init_router: go"; };
#                 };

#                 xtr::make_thread  "topwin_to_widget"  init_router;


#                 (kidplug, top_window, wm_window_delete_slot);
#           };                                                                          # fun make_hostwindow_to_widget_router

    };                                                                                  # package toplevel_window

end;


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext