PreviousUpNext

15.4.1618  src/lib/x-kit/xclient/src/window/draw-imp-old.pkg

## draw-imp-old.pkg
#
# The newworld version of this package is:   src/lib/x-kit/xclient/src/window/xserver-ximp.pkg
#
# TODO
#  - optimize the case where successive draw ops ("DOPs") use the same pen.
#  - All window configuration operations (Resize, Move, Pop/Push, Create &
#    Delete) should go through the draw imp. XXX BUGGO FIXME
#
# Nomenclature:  "gc" means "graphics context" throughout this file.

# 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 g2d =  geometry2d;                          # geometry2d                    is from   src/lib/std/2d/geometry2d.pkg
    package p2g =  pen_to_gcontext_imp_old;             # pen_to_gcontext_imp_old       is from   src/lib/x-kit/xclient/src/window/pen-to-gcontext-imp-old.pkg
    package pg  =  pen_guts;                            # pen_guts                      is from   src/lib/x-kit/xclient/src/window/pen-guts.pkg
    package v2w =  value_to_wire;                       # value_to_wire                 is from   src/lib/x-kit/xclient/src/wire/value-to-wire.pkg
    package vu8 =  vector_of_one_byte_unts;             # vector_of_one_byte_unts       is from   src/lib/std/src/vector-of-one-byte-unts.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
    package xtr =  xlogger;                             # xlogger                       is from   src/lib/x-kit/xclient/src/stuff/xlogger.pkg
    #
    trace =  xtr::log_if  xtr::io_logging  0;           # Conditionally write strings to tracing.log or whatever.
herein


    package   draw_imp_old
    : (weak)  Draw_Imp_Old                              # Draw_Imp_Old                  is from   src/lib/x-kit/xclient/src/window/draw-imp-old.api
    {
        package s {
            #
            Mapped_State                                # These are the messages we receive via our mappedstate_slot from xsession and hostwindow-to-widget-router.
              = HOSTWINDOW_IS_NOW_UNMAPPED
              | HOSTWINDOW_IS_NOW_MAPPED
              | FIRST_EXPOSE
              ;
        };

        package t {
            #
            Poly_Text
              = TEXT  (Int, String)
              | FONT  xt::Font_Id
              ;
        };

        package o {
            Draw_Opcode
              = POLY_POINT     (Bool, List( g2d::Point ))
              | POLY_LINE      (Bool, List( g2d::Point ))
              | FILL_POLY      (xt::Shape, Bool, List( g2d::Point ))
              | POLY_SEG       List( g2d::Line  )
              | POLY_BOX       List( g2d::Box   )
              | POLY_FILL_BOX  List( g2d::Box   )
              | POLY_ARC       List( g2d::Arc64 )
              | POLY_FILL_ARC  List( g2d::Arc64 )
              | COPY_AREA
                    ( g2d::Point,
                      xt::Xid,
                      g2d::Box,
                      Oneshot_Maildrop( Void -> List( g2d::Box ) )
                    )
              | COPY_PLANE
                    ( g2d::Point,
                      xt::Xid,
                      g2d::Box,
                      Int,
                      Oneshot_Maildrop (Void -> List( g2d::Box ) )
                    )
              | COPY_PMAREA    (g2d::Point, xt::Xid, g2d::Box)
              | COPY_PMPLANE   (g2d::Point, xt::Xid, g2d::Box, Int)
              | CLEAR_AREA      g2d::Box
              | PUT_IMAGE  {
                    to_point: g2d::Point,
                    size:     g2d::Size,
                    depth:    Int,
                    lpad:     Int,
                    format:   xt::Image_Format,
                    data:     vu8::Vector
                  }
              | POLY_TEXT8   (xt::Font_Id, g2d::Point, List( t::Poly_Text ))
              | IMAGE_TEXT8  (xt::Font_Id, g2d::Point, String)
              ;
        };

        package i {
            #
            Destroy_Item
              = WINDOW  xt::Window_Id
              | PIXMAP  xt::Pixmap_Id
              ;
        };

        package d {
            Draw_Op
              = DRAW  {
                  to:    xt::Xid,
                  pen:   pg::Pen,
                  op:    o::Draw_Opcode
                }
              | DESTROY    i::Destroy_Item
              | FLUSH      Oneshot_Maildrop( Void )             # Used (only) by  drawable_of_rw_pixmap() and make_unbuffered_drawable()  in  src/lib/x-kit/xclient/src/window/draw-types-old.pkg 
              | THREAD_ID  Oneshot_Maildrop( Int  )
              ;
        };

        /* +DEBUG 
        fun dop_to_string (o::POLY_POINT    _) = "PolyPoint";
            dop_to_string (o::POLY_LINE     _) = "PolyLine";
            dop_to_string (o::POLY_SEG      _) = "PolySeg";
            dop_to_string (o::FILL_POLY     _) = "PolyFillPoly";
            dop_to_string (o::POLY_BOX      _) = "PolyRect";
            dop_to_string (o::POLY_FILL_BOX _) = "PolyFillRect";
            dop_to_string (o::POLY_ARC      _) = "PolyArc";
            dop_to_string (o::POLY_FILL_ARC _) = "PolyFillArc";
            dop_to_string (o::COPY_AREA     _) = "CopyArea";
            dop_to_string (o::COPY_PLANE    _) = "CopyPlane";
            dop_to_string (o::COPY_PMAREA   _) = "CopyPMArea";
            dop_to_string (o::COPY_PMPLANE  _) = "CopyPMPlane";
            dop_to_string (o::CLEAR_AREA    _) = "ClearArea";
            dop_to_string (o::PUT_IMAGE     _) = "PutImage";
            dop_to_string (o::POLY_TEXT8    _) = "PolyText8";
            dop_to_string (o::IMAGE_TEXT8   _) = "ImageText8";
        end;
         -DEBUG */


        stipulate

            # Maximum number of drawing commands
            # to buffer before flushing.
            #
            full_buffer_size = 16;

            my (|)  =  unt::bitwise_or;
            my (<<) =  unt::(<<);

            infix my | <<;

            # Officially Mythryl does not have pointer equality,
            # but we do it here anyway for speed.  Naughty! :-)
            #
            fun pen_eq
                ( a:  pg::Pen,
                  b:  pg::Pen
                )
                =
                {   ((unsafe::cast a): Int)
                    ==
                    ((unsafe::cast b): Int);
                };

            # Bitmasks for the various components of a pen.
            # These should track the slot numbers given in PenValues.

            pen_function        = (0u1 << 0u0);
            pen_plane_mask      = (0u1 << 0u1);

            pen_foreground      = (0u1 << 0u2);
            pen_background      = (0u1 << 0u3);

            pen_line_width      = (0u1 << 0u4);
            pen_line_style      = (0u1 << 0u5);

            pen_cap_style       = (0u1 << 0u6);
            pen_join_style      = (0u1 << 0u7);

            pen_fill_style      = (0u1 << 0u8);
            pen_fill_rule       = (0u1 << 0u9); 

            pen_tile            = (0u1 << 0u10);
            pen_stipple         = (0u1 << 0u11);

            pen_tile_stip_origin= (0u1 << 0u12);
            pen_subwindow_mode  = (0u1 << 0u13);

            pen_clip_origin     = (0u1 << 0u14);
            pen_clip_mask       = (0u1 << 0u15);

            pen_dash_offset     = (0u1 << 0u16);
            pen_dash_list       = (0u1 << 0u17);

            pen_arc_mode        = (0u1 << 0u18);
            pen_exposures       = 0u0; #  (0u1 << 0u19) 

            stipulate
                standard_pen_components                         # The standard pen components used by most ops.
                    #
                    = pen_function
                    | pen_plane_mask
                    | pen_subwindow_mode
                    | pen_clip_origin
                    | pen_clip_mask
                    | pen_foreground
                    | pen_background
                    | pen_tile
                    | pen_stipple
                    | pen_tile_stip_origin
                    ;

                standard_linedrawing_pen_components             # The pen components used by line-drawing operations.
                    #
                    =  standard_pen_components
                    | pen_line_width
                    | pen_line_style
                    | pen_cap_style
                    | pen_join_style
                    | pen_fill_style
                    | pen_dash_offset
                    | pen_dash_list
                    ;
            herein

                fun pen_vals_used (o::POLY_POINT    _)  =>  standard_pen_components;
                    pen_vals_used (o::COPY_PMAREA   _)  =>  standard_pen_components;
                    pen_vals_used (o::COPY_PMPLANE  _)  =>  standard_pen_components;
                    pen_vals_used (o::PUT_IMAGE     _)  =>  standard_pen_components;
                    pen_vals_used (o::IMAGE_TEXT8   _)  =>  standard_pen_components;
                    #
                    pen_vals_used (o::POLY_TEXT8    _)  => (standard_pen_components | pen_fill_style);
                    pen_vals_used (o::FILL_POLY     _)  => (standard_pen_components | pen_fill_style);
                    pen_vals_used (o::POLY_FILL_BOX _)  => (standard_pen_components | pen_fill_style);
                    pen_vals_used (o::POLY_FILL_ARC _)  => (standard_pen_components | pen_fill_style);
                    #
                    pen_vals_used (o::COPY_AREA     _)  =>  standard_pen_components | pen_exposures;
                    pen_vals_used (o::COPY_PLANE    _)  =>  standard_pen_components | pen_exposures;
                    #
                    pen_vals_used (o::POLY_LINE     _)  =>  standard_linedrawing_pen_components;
                    pen_vals_used (o::POLY_SEG      _)  =>  standard_linedrawing_pen_components;
                    pen_vals_used (o::POLY_BOX      _)  =>  standard_linedrawing_pen_components;
                    pen_vals_used (o::POLY_ARC      _)  =>  standard_linedrawing_pen_components;
                    #
                    pen_vals_used (o::CLEAR_AREA    _)  => 0u0;
                end;
            end;

#           stipulate

#               include package   value_to_wire;

#           herein

                fun send_draw_op (send_xrequest, send_xrequest_and_handle_exposures)
                    =
                    \\  (to, gc_id, _, o::POLY_POINT (rel, points))
                            =>
#                           send_xrequest (v2w::encode_poly_point { drawable=>to, gc_id, items=>points, relative=>rel } );      # Replaced by below code.
                            {
                                # Discovered there's a limit to the number
                                # of points that can be sent to the X server.
                                # It's less than 65535, but at least 65400.
                                # I figure this is close enough:              -- Hue White 2011-11-24
                                #
                                x_limit = 65400;

                                send_xrequests points
                                where
                                    fun send_xrequests points
                                        =
                                        if (list::length(points) <= x_limit)
                                            #
                                            send_xrequest (v2w::encode_poly_point { drawable=>to, gc_id, items=>points, relative=>rel } );
                                        else
                                            send_xrequest (v2w::encode_poly_point { drawable=>to, gc_id, items=>(list::take_n(points, x_limit)), relative=>rel } );
                                            send_xrequests (list::drop_n(points, x_limit));
                                        fi;
                                end;
                            };

                        (to, gc_id, _, o::POLY_LINE (rel, points))
                            =>
                            send_xrequest (v2w::encode_poly_line { drawable=>to, gc_id, items=>points, relative=>rel } );

                        (to, gc_id, _, o::POLY_SEG lines)
                            =>
                            send_xrequest (v2w::encode_poly_segment { drawable=>to, gc_id, items=>lines } );

                        (to, gc_id, _, o::FILL_POLY (shape, rel, points))
                            =>
#                           send_xrequest (v2w::encode_fill_poly { drawable=>to, gc_id, points, relative=>rel, shape } );
                            {
                                msg = v2w::encode_fill_poly { drawable=>to, gc_id, points, relative=>rel, shape };

                                send_xrequest msg;
                            };

                        (to, gc_id, _, o::POLY_BOX boxes)
                            =>
                            send_xrequest (v2w::encode_poly_box { drawable=>to, gc_id, items=>boxes } );

                        (to, gc_id, _, o::POLY_FILL_BOX boxes)
                            =>
                            send_xrequest (v2w::encode_poly_fill_box { drawable=>to, gc_id, items=>boxes } );

                        (to, gc_id, _, o::POLY_ARC arcs)
                            =>
                            send_xrequest (v2w::encode_poly_arc { drawable=>to, gc_id, items=>arcs } );

                        (to, gc_id, _, o::POLY_FILL_ARC arcs)
                            =>
                            send_xrequest (v2w::encode_poly_fill_arc { drawable=>to, gc_id, items=>arcs } );

                        (to, gc_id, _, o::COPY_AREA (pt, from, box, sync_v))
                            =>
                            {   (g2d::box::upperleft_and_size  box)
                                    ->
                                    (p, size);

                                send_xrequest_and_handle_exposures (v2w::encode_copy_area { gc_id, from, to, from_point=>p, size, to_point=>pt }, sync_v);
                            };

                        (to, gc_id, _, o::COPY_PLANE (pt, from, box, plane, sync_v))
                            =>
                            {   (g2d::box::upperleft_and_size  box)
                                    ->
                                    (p, size);

                                send_xrequest_and_handle_exposures (v2w::encode_copy_plane { gc_id, from, to, from_point=>p, size, to_point=>pt, plane }, sync_v);
                            };

                        (to, gc_id, _, o::COPY_PMAREA (pt, from, box))
                            =>
                            {   (g2d::box::upperleft_and_size  box)
                                    ->
                                    (p, size);

                                send_xrequest (v2w::encode_copy_area { gc_id, from, to, from_point=>p, size, to_point=>pt });
                            };

                        (to, gc_id, _, o::COPY_PMPLANE (pt, from, box, plane))
                            =>
                            {   (g2d::box::upperleft_and_size  box)
                                    ->
                                    (p, size);

                                send_xrequest (v2w::encode_copy_plane { gc_id, from, to, from_point=>p, size, to_point=>pt, plane });
                            };

                        (to, _, _, o::CLEAR_AREA box)
                            =>
                            send_xrequest (v2w::encode_clear_area { window_id=>to, box, exposures => FALSE } );

                        (to, gc_id, _, o::PUT_IMAGE im)
                            =>
                            send_xrequest
                                (v2w::encode_put_image
                                  { drawable => to,
                                    gc_id,
                                    depth  => im.depth,
                                    to     => im.to_point,
                                    size   => im.size,
                                    lpad   => im.lpad,
                                    format => im.format,
                                    data   => im.data
                                  }
                                );


                        (to, gc_id, _, o::IMAGE_TEXT8(_, point, string))
                            =>
                            send_xrequest (v2w::encode_image_text8 { drawable=>to, gc_id, point, string } );

                        (to, gc_id, current_font_id, o::POLY_TEXT8 (font_id, point, txt_items))
                            =>
                            {   last_font_id =  f (font_id, txt_items)
                                            where
                                                fun f (last_font_id, [])               =>  last_font_id;
                                                    f (last_font_id, (t::FONT id) ! r) =>  f (id, r);
                                                    f (last_font_id, _ ! r)            =>  f (last_font_id, r);
                                                end;
                                            end;

                                txt_items =     last_font_id == current_font_id
                                                    ?? txt_items
                                                    :: txt_items @ [t::FONT current_font_id];

                                txt_items =     font_id == current_font_id
                                                    ?? txt_items
                                                    :: (t::FONT font_id) ! txt_items;


                                fun split_delta (0, l)  =>  l;
                                    #
                                    split_delta (i, l)  =>  if   (i < -128)   split_delta (i + 128, -128 ! l);
                                                            elif (i >  127)   split_delta (i - 127,  127 ! l);
                                                            else                                       i ! l ;
                                                            fi;
                                end;


                                # Split a string into legal
                                # lengths for a PolyText8 command 
                                #
                                fun split_text "" =>   [];
                                    #
                                    split_text s  =>    if (n <= 254)  [s];
                                                        else           split (0, []);
                                                        fi
                                                        where
                                                            n = string::length_in_bytes s;

                                                            fun split (i, l)
                                                                =
                                                                n - i  > 254
                                                                ??  split (i+254,  substring (s, i, 254) ! l)
                                                                ::  list::reverse (substring (s, i, n-i) ! l);
                                                        end;
                                end;


                                fun split_item (t::FONT id)
                                        =>
                                        [xt::FONT_ITEM id];

                                    split_item (t::TEXT (delta, s))
                                        =>
                                        case (split_delta (delta, []), split_text s)
                                            #
                                            ([], []) =>   [];
                                            ([], sl) =>   (map (\\ s = xt::TEXT_ITEM (0,  s)) sl);
                                            (dl, []) =>   (map (\\ n = xt::TEXT_ITEM (n, "")) dl);

                                            ([d], s ! sr)
                                                =>
                                                (xt::TEXT_ITEM (d, s) ! (map (\\ s = xt::TEXT_ITEM (0, s)) sr));

                                            (d ! dr, s ! sr)
                                                =>
                                                ((map (\\ n = xt::TEXT_ITEM (n, "")) dr)
                                                 @ (xt::TEXT_ITEM (d, s) ! (map (\\ s = xt::TEXT_ITEM (0, s)) sr)));
                                        esac;

                                end;

                                do_items =  fold_backward
                                                (\\ (item, l) =  (split_item item) @ l)
                                                [];

                                send_xrequest
                                    (v2w::encode_poly_text8
                                      {
                                        gc_id,
                                        point,
                                        drawable =>  to,
                                        items    =>  do_items txt_items
                                      }
                                    );
                            };                                                                                  # o::POLY_TEXT8
                    end;

#           end;                                # stipulate


            # Flush a list of drawing commands out to the sequencer.
            # This means acquiring actual X-server graphics contexts
            # for the operations from graphics_context_cache:
            #
            fun flush_buf (gc_cache, connection)
                =
                flush_buf'
                where 

                    Gc_Info
                      = NO_GC
                      | NO_FONT
                      | WITH_FONT xt::Font_Id
                      | SET_FONT  xt::Font_Id
                      ;

                    allot_gc                =   p2g::allocate_graphics_context                  gc_cache;
                    free_gc                 =   p2g::free_graphics_context                      gc_cache;

                    allot_gc_with_font      =   p2g::allocate_graphics_context_with_font        gc_cache;
                    allot_gc_and_set_font   =   p2g::allocate_graphics_context_and_set_font     gc_cache;
                    free_gc_and_font        =   p2g::free_graphics_context_and_font             gc_cache;

                    send_dop =  send_draw_op
                                  ( xok::send_xrequest                       connection,
                                    xok::send_xrequest_and_handle_exposures  connection
                                  );

                    # Our first argument is a list of X drawing operations
                    # to be performed.  For efficiency, we want to avoid
                    # switching graphics contexts needlessly, so we break our
                    # argument draw-op list into a sequence of sublists,
                    # each of which can be performed using a single gc.
                    # 
                    fun batch_drawops ([], results)
                            =>
                            results;                                                                    # No more input -- done. (Why don't we reverse it?)

                        batch_drawops
                            ( draw_ops as (first_op ! _),                                               # Input drawops list.
                              results                                                                   # Batch accumulator.
                            )
                            =>
                            {   (find_max_prefix (draw_ops, NO_GC, first_op.pen, 0u0, []))
                                    ->
                                    (remaining_draw_ops, gc_usage, pen, mask, max_prefix);

                                batch_drawops (remaining_draw_ops, (gc_usage, pen, mask, max_prefix) ! results);
                            }
                            where
                                fun gc_usage_of (o::CLEAR_AREA _)                =>   NO_GC;
                                    gc_usage_of (o::POLY_TEXT8  (font_id, _, _)) =>   WITH_FONT font_id;
                                    gc_usage_of (o::IMAGE_TEXT8 (font_id, _, _)) =>   SET_FONT  font_id;
                                    gc_usage_of op                               =>   NO_FONT;
                                end;


                                fun extend_mask (m, op)
                                    =
                                    m | (pen_vals_used op);


                                # We are given a list of X drawing operations to do.
                                # Our job is to find the maximal prefix of this list
                                # which can all use the same graphics context:
                                # 
                                fun find_max_prefix (arg as ([], _, _, _, _))
                                        =>
                                        arg;

                                    find_max_prefix (arg as ( { to, pen, op } ! rest, gc_usage, first_pen, used_mask, prefix))
                                        =>
                                        if (not (pen_eq (pen, first_pen)))
                                            #
                                            arg;
                                        else
                                            case (gc_usage, gc_usage_of op)
                                                #
                                                (_, NO_GC)
                                                    =>
                                                    find_max_prefix (rest, gc_usage, first_pen, used_mask,                                (to, op) ! prefix);

                                                (NO_GC, new_gc_usage)
                                                    =>
                                                    find_max_prefix (rest, new_gc_usage, first_pen, pen_vals_used op,                     (to, op) ! prefix);

                                                (_, NO_FONT)
                                                    =>
                                                    find_max_prefix (rest, gc_usage, first_pen, extend_mask (used_mask, op),              (to, op) ! prefix);

                                                (SET_FONT font_id, WITH_FONT _)
                                                    =>
                                                    find_max_prefix (rest, SET_FONT font_id, first_pen, extend_mask (used_mask, op),      (to, op) ! prefix);

                                                (_, WITH_FONT font_id)
                                                    =>
                                                    find_max_prefix (rest, WITH_FONT font_id, first_pen, extend_mask (used_mask, op),     (to, op) ! prefix);

                                                (SET_FONT font_id1, SET_FONT font_id2)
                                                    =>
                                                    if (font_id1 == font_id2)
                                                        #
                                                        find_max_prefix (rest, SET_FONT font_id1, first_pen, extend_mask (used_mask, op), (to, op) ! prefix);
                                                    else
                                                        arg;
                                                    fi;

                                                (_, SET_FONT font_id)
                                                    =>
                                                    find_max_prefix (rest, SET_FONT font_id, first_pen, extend_mask (used_mask, op),      (to, op) ! prefix);
                                            esac;
                                        fi;
                                end;
                            end;        
                    end;                                                # fun batch_drawops


                    fun send_draw_ops (gc, initial_font_id)
                        =
                        draw
                        where 
                            fun draw [] =>   ();
                                #
                                draw ((to, op) ! r)
                                    =>
                                    {   send_dop (to, gc, initial_font_id, op);
                                        draw r;
                                    };
                            end;

                        end;


                    xid0 =   xt::xid_from_unt  0u0;


                    fun draw_batch (NO_GC, _, _, ops)
                            =>
                            send_draw_ops (xid0, xid0) ops;

                        draw_batch (NO_FONT, pen, mask, ops)
                            =>
                            {   gc =   allot_gc { pen, used => mask };
                                #
                                send_draw_ops (gc, xid0) ops;
                                #
                                free_gc gc;
                            };

                        draw_batch (WITH_FONT font_id, pen, mask, ops)
                            =>
                            {   (allot_gc_with_font { pen, used => mask, font_id })
                                    ->
                                    (gc, init_font_id);

                                #
                                send_draw_ops (gc, init_font_id) ops;
                                #
                                free_gc_and_font gc;
                            };

                        draw_batch (SET_FONT font_id, pen, mask, ops)
                            =>
                            {   gc =   allot_gc_and_set_font { pen, used => mask, font_id };
                                #
                                send_draw_ops (gc, font_id) ops;
                                #
                                free_gc_and_font gc;
                            };
                    end;

                    draw_all_batches =  apply  draw_batch;

                    fun flush_buf'  buf
                        =
                        {   draw_all_batches (batch_drawops (buf, []));
                            #
                            xok::flush_xsocket connection;
                        };

                end;                    # fun flush_buf 


            # Insert a drawing command into the buffer,
            # checking for possible batching of operations.
            # BATCHING NOT IMPLEMENTED YET      XXX BUGGO FIXME
            #
            fun batch_cmd (commands_in_buffer, cmd, last, rest)
                =
                (commands_in_buffer+1, cmd ! last ! rest);


            fun destroy_window_or_pixmap  xsocket  (i::WINDOW window_id)
                    =>
                    {   xok::send_xrequest xsocket (v2w::encode_destroy_window { window_id } );
                        xok::flush_xsocket xsocket;
                    };

                destroy_window_or_pixmap  xsocket  (i::PIXMAP pixmap)
                    =>
                    {   xok::send_xrequest xsocket (v2w::encode_free_pixmap { pixmap } );
                        xok::flush_xsocket xsocket;
                    };
            end;



        herein

            # We get called two places:
            #     src/lib/x-kit/xclient/src/window/xsession-old.pkg
            #     src/lib/x-kit/xclient/src/window/hostwindow-to-widget-router-old.pkg
            #
            fun make_draw_imp
                  (
                    set_mappedstate':                   Mailop( s::Mapped_State ),
                    gc_cache:                           p2g::Pen_To_Gcontext_Imp,
                    xsocket:                            xok::Xsocket
                  )
                =
                {   # Need to check state transitions to insure no deadlock *  XXX BUGGO FIXME

                    plea_slot    =   make_mailslot ();
                    plea'        =   take_from_mailslot'  plea_slot;

                    flush        =   flush_buf (gc_cache, xsocket);

                    flush_delay' =   timeout_in' 0.04;

                    destroy_window_or_pixmap'
                        =
                        destroy_window_or_pixmap  xsocket;

                    # The draw_imp has two operating states,
                    # depending on whether its hostwindow
                    # is mapped or unmapped, each represented
                    # by a loop function.

                    # Unmapped state is easy -- we just
                    # discard all DRAW commands:   :-)
                    #   
                    fun hostwindow_is_unmapped_loop ()
                        =
                        do_one_mailop [
                            plea'            ==>  do_plea,
                            set_mappedstate' ==>  set_mappedstate
                        ]
                        where
                            fun set_mappedstate s::HOSTWINDOW_IS_NOW_MAPPED   =>  hostwindow_is_mapped_loop (0, []);
                                set_mappedstate s::HOSTWINDOW_IS_NOW_UNMAPPED =>  hostwindow_is_unmapped_loop ();
                                #
                                set_mappedstate _                            =>  (xgripe::impossible "[draw_mp (unmapped): bad config command]");
                            end;

                            fun do_plea (d::DESTROY id)                      =>  {   destroy_window_or_pixmap'  id;     hostwindow_is_unmapped_loop ();   };
                                do_plea _                                    =>                                         hostwindow_is_unmapped_loop ();
                            end;
                        end

                    also
                    fun hostwindow_is_mapped_loop (_, [])
                            =>
                            do_one_mailop [
                                plea'            ==>  do_plea,
                                set_mappedstate' ==>  set_mappedstate
                            ]
                            where
                                fun set_mappedstate s::HOSTWINDOW_IS_NOW_UNMAPPED =>  hostwindow_is_unmapped_loop ();
                                    set_mappedstate s::HOSTWINDOW_IS_NOW_MAPPED          =>  hostwindow_is_mapped_loop (0, []);
                                    #
                                    set_mappedstate _                            =>  xgripe::impossible "[drawimp (mapped): bad mapped-state command]";
                                end;

                                fun do_plea (d::DRAW m)                          =>  {                                                                          hostwindow_is_mapped_loop (1, [m]);     };
                                    do_plea (d::FLUSH flush_done_oneshot)        =>  {   put_in_oneshot (flush_done_oneshot, ());                               hostwindow_is_mapped_loop (0, [ ]);     };      # Buffer is empty so FLUSH is a no-op.
                                    do_plea (d::THREAD_ID thread_id_oneshot)     =>  {   put_in_oneshot (thread_id_oneshot, get_current_microthread's_id());    hostwindow_is_mapped_loop (0, [ ]);     };
                                    do_plea (d::DESTROY id)                      =>  {   destroy_window_or_pixmap'  id;                                         hostwindow_is_mapped_loop (0, [ ]);     };
                                end;
                            end;

                        hostwindow_is_mapped_loop (commands_in_buffer, buf as (last_command ! rest))
                            =>
                            if (commands_in_buffer > full_buffer_size)
                                #
                                flush buf;
                                hostwindow_is_mapped_loop (0, []);
                            else
                                do_one_mailop [
                                    flush_delay'     ==>   (\\ _ = {  flush buf;  hostwindow_is_mapped_loop (0, []);  }),
                                    plea'            ==>   do_plea,
                                    set_mappedstate' ==>   set_mappedstate
                                ];
                            fi
                            where
                                fun set_mappedstate s::HOSTWINDOW_IS_NOW_UNMAPPED =>    hostwindow_is_unmapped_loop ();
                                    set_mappedstate s::HOSTWINDOW_IS_NOW_MAPPED          =>     hostwindow_is_mapped_loop (commands_in_buffer, buf);
                                    #
                                    set_mappedstate _                            =>     xgripe::impossible "[drawimp (mapped): bad mapped-state command]";
                                end;


                                fun do_plea (d::DRAW m)
                                         =>
                                         hostwindow_is_mapped_loop (batch_cmd (commands_in_buffer, m, last_command, rest));

                                    do_plea (d::DESTROY id)
                                         =>
                                         {   flush buf;
                                             destroy_window_or_pixmap'  id;
                                             hostwindow_is_mapped_loop (0, []);
                                         };

                                    do_plea (d::FLUSH flush_done_oneshot)
                                         =>
                                         {   flush buf;
                                             put_in_oneshot (flush_done_oneshot, ());
                                             hostwindow_is_mapped_loop (0, []);
                                         };

                                    do_plea (d::THREAD_ID  thread_id_oneshot)
                                         =>
                                         {   put_in_oneshot (thread_id_oneshot, get_current_microthread's_id());
                                             #
                                             hostwindow_is_mapped_loop (commands_in_buffer, buf);
                                         };
                                end;
                            end;
                    end;                                                                                # hostwindow_is_mapped_loop

                    fun start_draw_imp ()
                        =
                        {
                            # Wait for FIRST_EXPOSE,
                            # then enter main loop:
                            #
                            case (block_until_mailop_fires  set_mappedstate')
                                #
                                s::FIRST_EXPOSE =>   hostwindow_is_mapped_loop (0, []);
                                 _              =>   start_draw_imp ();
                            esac;
                        };

                    xlogger::make_thread  "draw_imp"  start_draw_imp;

                    \\ msg =   put_in_mailslot  (plea_slot, msg);

                };              # fun make_draw_imp
        end;                    # stipulate
    };                          # package draw_imp 
end;                            # stipulate



Comments and suggestions to: bugs@mythryl.org

PreviousUpNext