PreviousUpNext

15.4.1652  src/lib/x-kit/xclient/src/window/window-property-imp-old.pkg

## window-property-imp-old.pkg
#
# The property imp maps PropertyChange X-events
# to those threads that are interested in them
# and manages a collection of unique property names.
#
# This could be done by two separate threads
# but it simplifies things to keep all of the
# property stuff in one place.

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





###                   "Truth is much too complicated to
###                    allow anything but approximations."
###
###                                -- Johnny von Neumann

stipulate
    include package   threadkit;                                # threadkit                     is from   src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg
    #
    package aht = atom_table;                                   # atom_table                    is from   src/lib/x-kit/xclient/src/iccc/atom-table.pkg
    package ai  = atom_imp_old;                                 # atom_imp_old                  is from   src/lib/x-kit/xclient/src/iccc/atom-imp-old.pkg
    package dy  = display_old;                                  # display_old                   is from   src/lib/x-kit/xclient/src/wire/display-old.pkg
    package ts  = xserver_timestamp;                            # xserver_timestamp             is from   src/lib/x-kit/xclient/src/wire/xserver-timestamp.pkg
    package xe  = xevent_types;                                 # xevent_types                  is from   src/lib/x-kit/xclient/src/wire/xevent-types.pkg
    package xok = xsocket_old;                                  # xsocket_old                   is from   src/lib/x-kit/xclient/src/wire/xsocket-old.pkg
    package xt  = xtypes;                                       # xtypes                        is from   src/lib/x-kit/xclient/src/wire/xtypes.pkg
herein


    package   window_property_imp_old
    : (weak)  Window_Property_Imp_Old                           # Window_Property_Imp_Old       is from   src/lib/x-kit/xclient/src/window/window-property-imp-old.api
    {

        Atom = xt::Atom;

        fmt_prop_name                                           # Make unique property names.
            =
            sfprintf::sprintf' "_XKIT_%d";

        fun make_prop_name n
            =
            fmt_prop_name [sfprintf::INT n];

        Property_Change = NEW_VALUE | DELETED;                  # Observed changes to property values:

        # Property imp requests:
        #
        Plea_Mail
            = 
            WATCH_PROP  {
                name:       Atom,                               # Watched property's name.
                window:     xt::Window_Id,                      # Watched property's window.
                is_unique:  Bool,                               # TRUE, if the property is an internally 
                                                                # allocated uniquely named property. 

                notify_slot                                     # Slot which gets the change notifications.
                    :
                    Mailslot( (Property_Change, ts::Xserver_Timestamp) )

              }
          | ALLOC_PROP  (xt::Window_Id, Oneshot_Maildrop( Atom ))
          ;

        # Representation of the
        # selection imp connection:
        #
        Window_Property_Imp
            =
            WINDOW_PROPERTY_IMP  {
                xsocket:     xok::Xsocket,
                plea_slot:   Mailslot( Plea_Mail )
            };

        # Watched property info:
        #
        Property_Info
            =
            {   window:     xt::Window_Id,
                watchers:   List( Mailslot( (Property_Change, ts::Xserver_Timestamp) ) ),
                is_unique:  Bool
            };

        # Operations on the property info tables.
        # Each item in the table is a list of
        # Property_Info values, one for each window
        # that has a property of the given name.
        #
        fun make_prop_table () :  aht::Hashtable( List( Property_Info ) )
            =
            aht::make_hashtable  { size_hint => 16,  not_found_exception => DIE "PropTable" };


        fun find_prop (table, window, name)
            =
            {   fun get []
                        =>
                        NULL;

                    get ((item:  Property_Info) ! r)
                        =>
                        item.window == window
                            ##
                            ??   THE item
                            ::   get r;
                end;

                case (aht::find table name)
                     #        
                     THE l =>  get l;
                     _     =>  NULL;
                esac;
            };

        # Insert a watcher of a property into the table. 
        #
        fun insert_watcher (table, window, name, watcher, is_unique)
            =
            {   fun get []
                        =>
                        [ { window => window, watchers => [watcher], is_unique } ];

                    get ((item:  Property_Info) ! r)
                        =>
                        if (item.window == window)
                            #
                            { window,
                              watchers  =>  watcher ! item.watchers,
                              is_unique =>  item.is_unique
                            }
                            !
                            r;
                        else
                            item ! (get r);
                        fi;
                end;

                case (aht::find table name)

                     NULL
                         =>
                         aht::set
                             table
                             (name, [{ window => window, watchers => [watcher], is_unique } ]);

                     THE l => aht::set table (name, get l);
                esac;
            };

        # Insert a unique property into the table.  Since the property is unique,
        # it should not be in the table.
        # NOTE: this will change if we do uniqueness by window.
        #
        fun insert_unique (table:  aht::Hashtable(  List(  Property_Info ) ), window, name)
            =
            aht::set table (name, [{ window => window, watchers => [], is_unique => TRUE } ]);


        fun remove_prop (table, window, name)
            =
            {
                fun get []
                        =>
                        xgripe::impossible "window_property_imp::remove_prop";

                    get ((item:  Property_Info) ! r)
                        =>
                        item.window == window   ??   r
                                                ::   item ! (get r);
                end;

                case (get (aht::get  table  name))
                    #         
                    [] =>  {   aht::drop table   name;       };
                    l  =>  {   aht::set  table  (name, l);   };
                esac;
            };

        fun make_window_property_imp (xdpy as { xsocket, ... }: dy::Xdisplay, atom_imp)
            =
            {   prop_table   =   make_prop_table ();            #  A table of watched properties 
                unique_props =   REF [];                                #  A list of unique property names 

                fun get_prop ()
                    =
                    get (0, *unique_props)
                    where 

                        fun get (n, [])
                                =>
                                {   atom =  ai::make_atom  atom_imp  (make_prop_name n);

                                    unique_props :=  (atom, REF FALSE) ! *unique_props;

                                    atom;
                                };

                            get (n, (atom, avail) ! r)
                                =>
                                if *avail
                                    #
                                    avail := FALSE;
                                    atom;
                                else
                                    get (n+1, r);
                                fi;
                        end;

                    end;

                fun free_prop name
                    =
                    get *unique_props
                    where 

                        fun get []
                                =>
                                xgripe::impossible "window_property_imp::free_prop";

                            get ((atom, avail) ! r)
                                =>
                                if (name == atom)
                                    #
                                    avail := TRUE;
                                else
                                    get r;
                                fi;
                        end;

                    end;


                # The X-event and request channels 
                #
                xevent_slot =   make_mailslot ();
                plea_slot   =   make_mailslot ();


                # Asynchronously send a message on a list of channels 
                #
                fun broadcast ([], msg)
                        =>
                        ();

                    broadcast (slot ! r, msg)
                        =>
                        {
                            make_thread "property imp broadcast"  {.  put_in_mailslot (slot, msg);  };
                            broadcast (r, msg);
                        };
                end;

                # Handle a selection related X-event 
                #
                fun do_xevent (xe::x::PROPERTY_NOTIFY { changed_window_id, atom, timestamp, deleted } )
                        =>
                        case (find_prop (prop_table, changed_window_id, atom), deleted)
                            #
                            (THE { watchers, ... }, FALSE)
                                =>
                                broadcast (watchers, (NEW_VALUE, timestamp));

                            (THE { watchers, is_unique, ... }, TRUE)
                                =>
                                {   broadcast (watchers, (DELETED, timestamp));
                                    remove_prop (prop_table, changed_window_id, atom);

                                    if is_unique    free_prop atom;   fi;
                                };

                            (NULL, _) => ();
                       esac;

                   do_xevent xevent
                       =>
                       xgripe::impossible "window_property_imp::make_server::do_xevent";
                end;

                fun do_plea (WATCH_PROP { name, window, is_unique, notify_slot } )
                        =>
                        insert_watcher (prop_table, window, name, notify_slot, is_unique);

                    do_plea (ALLOC_PROP (window, reply_1shot))
                        =>
                        {   name =   get_prop ();
                            #
                            insert_unique (prop_table, window, name);

                            put_in_oneshot (reply_1shot, name);
                        };
                end;

                # The imp loop:
                #
                fun loop ()
                    =
                    for (;;) {
                        #
                        do_one_mailop [
                            #
                            take_from_mailslot' xevent_slot ==>  do_xevent,
                            take_from_mailslot'   plea_slot ==>  do_plea
                        ];
                    };

                xlogger::make_thread  "window_property_imp"  loop;

                (xevent_slot, WINDOW_PROPERTY_IMP { xsocket, plea_slot } );

            };                                                          # fun make_window_property_imp

        fun plead (WINDOW_PROPERTY_IMP { plea_slot, ... }, plea)
            =
            put_in_mailslot (plea_slot, plea);


        # Return an event for monitoring
        # changes to a property's state: 
        #
        fun watch_property (imp, name, window, is_unique)
            =
            take_from_mailslot'  notify_slot
            where 
                notify_slot =   make_mailslot ();

                plead (
                    imp,
                    WATCH_PROP { name, window, is_unique, notify_slot }
                );
            end;

        # Generate a property on the specified window
        # that is guaranteed to be unique.

        fun unused_property (imp, window)
            =
            {   reply_1shot =  make_oneshot_maildrop ();
                #
                plead (imp, ALLOC_PROP (window, reply_1shot));

                get_from_oneshot  reply_1shot;
            };

    };                                                                  # package property-imp

end;


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext