PreviousUpNext

15.4.1467  src/lib/x-kit/widget/lib/ro-pixmap-ximp.pkg

## ro-pixmap-ximp.pkg
#
# Support for icons, button images
# and so forth:   Track what readonly
# windows we have on the X server and
# transparently load new ones as needed.
#

# Compiled by:
#     src/lib/x-kit/widget/xkit-widget.sublib

###            "Opportunity is missed by most people
###              because it is dressed in overalls
###               and looks like work."
###
###                          -- Thomas Edison


stipulate
    include package   threadkit;                                                # threadkit                     is from   src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg
    #
    package bio =  bitmap_io;                                                   # bitmap_io                     is from   src/lib/x-kit/draw/bitmap-io.pkg
    package fil =  file__premicrothread;                                        # file__premicrothread          is from   src/lib/std/src/posix/file--premicrothread.pkg
    package qk  =  quark;                                                       # quark                         is from   src/lib/x-kit/style/quark.pkg
    package xc  =  xclient;                                                     # xclient                       is from   src/lib/x-kit/xclient/xclient.pkg
    package rpp =  ro_pixmap_port;                                              # ro_pixmap_port                is from   src/lib/x-kit/widget/lib/ro-pixmap-port.pkg
    package cpm =  cs_pixmap;                                                   # cs_pixmap                     is from   src/lib/x-kit/xclient/src/window/cs-pixmap.pkg
    package rpm =  ro_pixmap;                                                   # ro_pixmap                     is from   src/lib/x-kit/xclient/src/window/ro-pixmap.pkg
herein

    package   ro_pixmap_ximp
    : (weak)  Ro_Pixmap_Ximp                                                    # Ro_Pixmap_Ximp                is from   src/lib/x-kit/widget/lib/ro-pixmap-ximp.api
    {
        Exports   = {                                                                           # Ports we export for use by other imps.
                      ro_pixmap_port:           rpp::Ro_Pixmap_Port                             # Requests from widget/application code.
                    };

        Imports   = {                                                                           # Ports we use which are exported by other imps.
                      name_to_cs_pixmap:        qk::Quark -> cpm::Cs_Pixmap
                    };

        Option = MICROTHREAD_NAME String;                                                       # 

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

        exception BAD_NAME;

        package qht
            =
            typelocked_hashtable_g (
                #
                Hash_Key   = qk::Quark;
                same_key   = qk::same;
                hash_value = qk::hash;
            );

        Window_Table
            =
            qht::Hashtable( rpm::Ro_Pixmap );

        Ro_Pixmap_Ximp_State                                                                    # Holds all mutable state maintained by ximp.
            =
            {
              window_table: Window_Table
            };

        Me_Slot = Mailslot(   { imports:                Imports,
                                me:                     Ro_Pixmap_Ximp_State,
                                run_gun':               Run_Gun,
                                end_gun':               End_Gun,
                                screen:                 xsession_junk::Screen,
                                name_to_cs_pixmap:      qk::Quark -> cpm::Cs_Pixmap
                              }
                          );

                                                                                    # typelocked_hashtable_g    is from   src/lib/src/typelocked-hashtable-g.pkg


        exception NOT_FOUND;

        Runstate =  {                                                                                                   # These values will be statically globally visible throughout the code body for the imp.
                      me:                               Ro_Pixmap_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.
                      screen:                           xsession_junk::Screen,
                      name_to_cs_pixmap:                qk::Quark -> cpm::Cs_Pixmap
                    };

        Client_Q    =   Mailqueue( Runstate -> Void );



        fun run ( client_q:                             Client_Q,                                                       # Requests from x-widgets and such via draw_imp, pen_imp or font_imp.
                  #
                  runstate as
                  {                                                                                                     # These values will be statically globally visible throughout the code body for the imp.
                    me:                                 Ro_Pixmap_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.
                    
                    screen:                             xsession_junk::Screen,
                    name_to_cs_pixmap:                  qk::Quark -> cpm::Cs_Pixmap
                  }
                )
            =
            loop ()
            where
                fun loop ()                                                                                             # Outer loop for the imp.
                    =
                    {   do_one_mailop' to [
                            #
                            end_gun'                       ==>  shut_down_ro_pixmap_ximp',
                            take_from_mailqueue' client_q  ==>  do_client_plea
                        ];

                        loop ();
                    }
                    where
                        fun do_client_plea thunk
                            =
                            thunk runstate;

                        fun shut_down_ro_pixmap_ximp' ()
                            =
                            thread_exit { success => TRUE };                                                            # Will not return.      
                    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;
                #
                ro_pixmap_port  = {
                                    get_ro_pixmap
                                  };

                to =  make_replyqueue ();

                put_in_oneshot (reply_oneshot, (me_slot, { ro_pixmap_port }));                                          # Return value from ro_pixmap_egg'().

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

                block_until_mailop_fires  run_gun';                                                                     # Wait for the starting gun.

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


                fun get_ro_pixmap  (name: String)
                    =
                    {   reply_1shot =  make_oneshot_maildrop ();
                        #
                        put_in_mailqueue (client_q,
                            #
                            \\ ({ me, screen, name_to_cs_pixmap, ... }: Runstate)
                                =
                                {   quark = qk::quark name;
                                    #
                                    result =    case (find_window quark)
                                                    #
                                                    NULL => make_window (name, quark);
                                                    s    => s;
                                                esac;

                                    put_in_oneshot (reply_1shot, result);
                                }
                                where
                                    note_window =  qht::set   me.window_table;
                                    find_window =  qht::find  me.window_table;

                                    # Parse file, being careful to close
                                    # it properly if an exception is raised:
                                    #
                                    fun parse_file (fd, parse)
                                        = 
                                        (parse fd
                                         then
                                             fil::close_input  fd
                                        ) 
                                        except
                                            e = {   fil::close_input  fd;
                                                    raise exception e;
                                                };

                                    fun make_window_from_file (name, quark)
                                        =
                                        {   file_name = substring (name, 1, size name - 1);
                                            #
                                            fd = fil::open_for_read  file_name;

                                            (parse_file (fd, bio::read_bitmap))
                                                ->
                                                { image, ... };

                                            t = rpm::make_readonly_pixmap_from_clientside_pixmap
                                                    screen
                                                    image;

                                            note_window (quark, t);

                                            THE t;
                                        };

                                    fun make_window_from_clientside_pixmap  quark
                                        =
                                        {   window =    rpm::make_readonly_pixmap_from_clientside_pixmap
                                                            screen
                                                            (name_to_cs_pixmap  quark);

                                            note_window (quark, window);

                                            THE window;
                                        };

                                    fun make_window (arg as (name, q))
                                        = 
                                        if (string::get_byte_as_char (name, 0) == '@')
                                            #
                                            make_window_from_file  arg;
                                        else
                                            make_window_from_clientside_pixmap  q;
                                        fi
                                        except _ = NULL;
                                end
                        );

                        get_from_oneshot  reply_1shot;
                    };
            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_ro_pixmap_egg                                                                                          # PUBLIC. PHASE 1: Construct our state and initialize from 'options'.
              (
                screen:                 xsession_junk::Screen,
                options:                List(Option)
              )
            =
            {   (process_options (options, { name => "ro_pixmap" }))
                    ->
                    { name };
        
                me =    {
                         window_table =>    qht::make_hashtable  { size_hint => 32,  not_found_exception => NOT_FOUND }
                        };

                \\ () = {   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
                                )
                                =
                                {       name_to_cs_pixmap =  imports.name_to_cs_pixmap;
                                    #
                                    put_in_mailslot  (me_slot, { me, imports, run_gun', end_gun', screen, name_to_cs_pixmap });
                                };

                            (exports, phase3);
                        };
            };
    };

end;


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext