PreviousUpNext

15.4.1466  src/lib/x-kit/xclient/pkg/window/cs-pixmap.pkg

## cs-pixmap.pkg                        "cs" == "client-side"
#
#   Client-side rectangular arrays of pixels,
#   Support for copying back and forth between them
#   and server-side windows makes them useful for
#   specifying icons, tiling patterns and other
#   client-originated image data intended for X display.
#
# See also:
#     src/lib/x-kit/xclient/pkg/window/ro-pixmap.pkg
#     src/lib/x-kit/xclient/pkg/window/window.pkg
#     src/lib/x-kit/xclient/pkg/window/rw-pixmap.pkg

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



#
# TODO                  XXX BUGGO FIXME
#   - support a left-pad
#   - support Z format



###                  "Science is what we understand well enough to explain
###                   to a computer.  Art is everything else we do."
###
###                                          -- Donald Knuth

stipulate
    include threadkit;                  # threadkit             is from   src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg
    #
    package w8v= vector_of_one_byte_unts;               # vector_of_one_byte_unts               is from   src/lib/std/src/vector-of-one-byte-unts.pkg
    package w8= one_byte_unt;                   # one_byte_unt                  is from   src/lib/std/one-byte-unt.pkg
    #
    package di  =  draw_imp;            # draw_imp              is from   src/lib/x-kit/xclient/pkg/window/draw-imp.pkg
    package dt  =  draw_types;          # draw_types            is from   src/lib/x-kit/xclient/pkg/window/draw-types.pkg
    package dy  =  display;             # display               is from   src/lib/x-kit/xclient/pkg/wire/display.pkg
    package xg  =  xgeometry;           # xgeometry             is from   src/lib/std/2d/xgeometry.pkg
    package sn  =  xsession;            # xsession              is from   src/lib/x-kit/xclient/pkg/window/xsession.pkg
    package w2v =  wire_to_value;       # wire_to_value         is from   src/lib/x-kit/xclient/pkg/wire/wire-to-value.pkg
    package wpm =  rw_pixmap;           # rw_pixmap             is from   src/lib/x-kit/xclient/pkg/window/rw-pixmap.pkg
    package v2w =  value_to_wire;       # value_to_wire         is from   src/lib/x-kit/xclient/pkg/wire/value-to-wire.pkg
    package xok =  xsocket;             # xsocket               is from   src/lib/x-kit/xclient/pkg/wire/xsocket.pkg
    package xt  =  xtypes;              # xtypes                is from   src/lib/x-kit/xclient/pkg/wire/xtypes.pkg
    package xtr =  xlogger;             # xlogger               is from   src/lib/x-kit/xclient/pkg/stuff/xlogger.pkg
    #
    trace =  xtr::log_if  xtr::io_logging;              # Conditionally write strings to tracing.log or whatever.
herein


    package   cs_pixmap
    : (weak)  Cs_Pixmap
    {
        exception BAD_CS_PIXMAP_DATA;

        w8vextract
            =
            vector_slice_of_one_byte_unts::to_vector
            o
            vector_slice_of_one_byte_unts::make_slice;

        Cs_Pixmap
            =
            CS_PIXMAP
              { size:  xg::Size,
                data:  List(  List(  vector_of_one_byte_unts::Vector ) )
              };

        # Two cs_pixmaps   are the same
        # iff their fields are the same:
        #
        fun same_cs_pixmap
            ( CS_PIXMAP { size => size1, data => data1 },
              CS_PIXMAP { size => size2, data => data2 }
            )
            =
            if (not (xg::size::eq (size1, size2)))
                #
                FALSE;
            else
                same_planes (data1, data2)
                where
                    fun same_plane ([], []) =>   TRUE;
                        same_plane (_,  []) =>   FALSE;
                        same_plane ([], _ ) =>   FALSE;

                        same_plane ( scanline1 ! rest1,
                                     scanline2 ! rest2
                                   )
                            =>
                            scanline1 == scanline2
                            and
                            same_plane (rest1, rest2);
                    end;

                    fun same_planes ([], []) =>   TRUE;
                        same_planes (_,  []) =>   FALSE;
                        same_planes ([], _ ) =>   FALSE;

                        same_planes ( plane1 ! rest1,
                                      plane2 ! rest2
                                    )
                            =>
                            same_plane (plane1, plane2)
                            and
                            same_planes (rest1, rest2);
                    end;
                end;
            fi;

        # Map a row of data coded as
        # a string to a bit representation.
        # The data may be either encoded
        # in hex (with a preceeding "0x")
        # or in binary (with a preceeding "0b"):
        #
        fun string_to_data (wid, s)
            =
            case (string::explode s)

                ('0' ! 'x' ! r)
                    =>
                    make_row (nbytes, r, [])
                    where
                        nbytes = ((wid + 7) / 8);   #  # of bytes per line 

                        fun cvt_char c
                            =
                            if (char::is_digit c)

                                 byte::char_to_byte c - byte::char_to_byte '0';
                            else
                                 if (char::is_hex_digit c)

                                      char::is_upper c
                                      ??  byte::char_to_byte c - byte::char_to_byte 'A'
                                      ::  byte::char_to_byte c - byte::char_to_byte 'a';
                                 else
                                      raise exception BAD_CS_PIXMAP_DATA;
                                 fi;
                            fi;

                        fun make_row (0, [], l) =>  w8v::from_list (reverse l);
                            make_row (0,  _, _) =>  raise exception BAD_CS_PIXMAP_DATA;

                            make_row (i, d1 ! d0 ! r, l)
                                =>
                                make_row (i - 1, r,
                                  w8::bitwise_or (w8::(<<) (cvt_char d1, 0u4), cvt_char d0) ! l);

                            make_row _
                                =>
                                raise exception BAD_CS_PIXMAP_DATA;
                        end;
                    end;

                ('0' ! 'b' ! r)
                    =>
                    make_row (wid, 0ux80, r, 0u0, [])
                    where
                        fun make_row (0, _, [], b, l)
                                =>
                                w8v::from_list (reverse (b ! l));

                            make_row (_, _, [], _, _)
                                =>
                                raise exception BAD_CS_PIXMAP_DATA;

                            make_row (i, 0u0, l1, b, l2)
                               =>
                               make_row (i, 0ux80, l1, 0u0, b ! l2);

                            make_row (i, m, '0' ! r, b, l)
                               =>
                               make_row (i - 1, w8::(>>) (m, 0u1), r, b, l);

                            make_row (i, m, '1' ! r, b, l)
                               =>
                               make_row (i - 1, w8::(>>) (m, 0u1), r, w8::bitwise_or (m, b), l);

                            make_row _
                                =>
                                raise exception BAD_CS_PIXMAP_DATA;
                        end;
                    end;

                _   => raise exception BAD_CS_PIXMAP_DATA;
            esac;


        # Reverse the bit-order of a byte 
        #
        fun rev_bits b                                  # XXX BUGGO FIXME this should be a general library routine somewhere.
            =
            {
                rev_table = byte::string_to_bytes "\
                      \\000\128\064\192\032\160\096\224\
                      \\016\144\080\208\048\176\112\240\
                      \\008\136\072\200\040\168\104\232\
                      \\024\152\088\216\056\184\120\248\
                      \\004\132\068\196\036\164\100\228\
                      \\020\148\084\212\052\180\116\244\
                      \\012\140\076\204\044\172\108\236\
                      \\028\156\092\220\060\188\124\252\
                      \\002\130\066\194\034\162\098\226\
                      \\018\146\082\210\050\178\114\242\
                      \\010\138\074\202\042\170\106\234\
                      \\026\154\090\218\058\186\122\250\
                      \\006\134\070\198\038\166\102\230\
                      \\022\150\086\214\054\182\118\246\
                      \\014\142\078\206\046\174\110\238\
                      \\030\158\094\222\062\190\126\254\
                      \\001\129\065\193\033\161\097\225\
                      \\017\145\081\209\049\177\113\241\
                      \\009\137\073\201\041\169\105\233\
                      \\025\153\089\217\057\185\121\249\
                      \\005\133\069\197\037\165\101\229\
                      \\021\149\085\213\053\181\117\245\
                      \\013\141\077\205\045\173\109\237\
                      \\029\157\093\221\061\189\125\253\
                      \\003\131\067\195\035\163\099\227\
                      \\019\147\083\211\051\179\115\243\
                      \\011\139\075\203\043\171\107\235\
                      \\027\155\091\219\059\187\123\251\
                      \\007\135\071\199\039\167\103\231\
                      \\023\151\087\215\055\183\119\247\
                      \\015\143\079\207\047\175\111\239\
                      \\031\159\095\223\063\191\127\255";

                w8v::get (rev_table, w8::to_int b);
            };

        # Routines to re-order bits and bytes to the server's format (stolen from
        # XPutImage::c in Xlib).  We represent data in the following format:
        #
        #   scan-line unit = 1 byte
        #   byte-order     = MSB first (doen't matter for 1-byte scan units)
        #   bit-order      = MSB first (bit 0 is leftmost on display)
        #
        # This is the "1Mm" format of XPutImage::c in Xlib.  The relevant lines
        # in the conversion table are:
        #
        #         1Mm 2Mm 4Mm 1Ml 2Ml 4Ml 1Lm 2Lm 4Lm 1Ll 2Ll 4Ll
        #   1Mm:   n   n   n   R   S   L   n   s   l   R   R   R
        #   1Ml:   R   R   R   n   s   l   R   S   L   n   n   n
        #
        #   legend:
        #               n   no changes
        #               s   reverse 8-bit units within 16-bit units
        #               l   reverse 8-bit units within 32-bit units
        #               R   reverse bits within 8-bit units
        #               S   s+R
        #               L   l+R

        fun no_swap x = x;

        fun swap_bits data
            =
            w8v::from_list (w8v::fold_right (fn (b, l) = rev_bits b ! l) [] data);

        fun explode_v data
            =
            w8v::fold_right (!) [] data;

        fun swap_two_bytes s
            =
            {   fun swap [] => [];
                    swap (a ! b ! r) => b ! a ! (swap r);
                    swap _ => (xgripe::impossible "[swap_two_bytes: bad image data]");
                end;

                w8v::from_list (swap (explode_v s));
            };

        fun swap_four_bytes s
            =
            {
                fun swap [] => [];
                    swap (a ! b ! c ! d ! r) => d ! c ! b ! a ! (swap r);
                    swap _ => (xgripe::impossible "[swap_four_bytes: bad image data]");
                end;

                w8v::from_list (swap (explode_v s));
            };

        fun swap_bits_and_two_bytes s
            =
            {
                fun swap [] => [];
                    swap (a ! b ! r) => (rev_bits b) ! (rev_bits a) ! (swap r);
                    swap _ => (xgripe::impossible "[swap_bits_and_two_bytes: bad image data]");
                end;

                w8v::from_list (swap (explode_v s));
            };

        fun swap_bits_and_four_bytes  s
            =
            {
                fun swap []
                        =>
                        [];

                    swap (a ! b ! c ! d ! r)
                        =>
                        (rev_bits d) ! (rev_bits c) ! (rev_bits b) ! (rev_bits a) ! (swap r);

                    swap _
                        =>
                        (xgripe::impossible "[swap_bits_and_four_bytes: bad image data]");
                end;

                w8v::from_list (swap (explode_v s));
            };

        fun swap_func ( xt::RAW8, xt::MSBFIRST, xt::MSBFIRST) => no_swap;
            swap_func (xt::RAW16, xt::MSBFIRST, xt::MSBFIRST) => no_swap;
            swap_func (xt::RAW32, xt::MSBFIRST, xt::MSBFIRST) => no_swap;
            swap_func ( xt::RAW8, xt::MSBFIRST, xt::LSBFIRST) => swap_bits;
            swap_func (xt::RAW16, xt::MSBFIRST, xt::LSBFIRST) => swap_bits_and_two_bytes;
            swap_func (xt::RAW32, xt::MSBFIRST, xt::LSBFIRST) => swap_bits_and_four_bytes;
            swap_func ( xt::RAW8, xt::LSBFIRST, xt::MSBFIRST) => no_swap;
            swap_func (xt::RAW16, xt::LSBFIRST, xt::MSBFIRST) => swap_two_bytes;
            swap_func (xt::RAW32, xt::LSBFIRST, xt::MSBFIRST) => swap_four_bytes;
            swap_func ( xt::RAW8, xt::LSBFIRST, xt::LSBFIRST) => swap_bits;
            swap_func (xt::RAW16, xt::LSBFIRST, xt::LSBFIRST) => swap_bits;
            swap_func (xt::RAW32, xt::LSBFIRST, xt::LSBFIRST) => swap_bits;
        end;

        fun pad_to_bits xt::RAW8 => 0u8;
            pad_to_bits xt::RAW16 => 0u16;
            pad_to_bits xt::RAW32 => 0u32;
        end;

        fun round_down (nbytes, pad)
            =
            unt::to_int_x(
              unt::bitwise_and (unt::from_int nbytes, unt::bitwise_not((pad_to_bits pad) - 0u1)));

        fun round_up (nbytes, pad)
            =
            {
                bits = (pad_to_bits pad) - 0u1;

                unt::to_int_x (unt::bitwise_and (unt::from_int nbytes + bits, unt::bitwise_not bits));
            };

        # Pad and re-order image data as necessary
        # to match the server's format.
        #
        stipulate

            pad1 = w8v::tabulate (1, fn _ = 0u0);
            pad2 = w8v::tabulate (2, fn _ = 0u0);
            pad3 = w8v::tabulate (3, fn _ = 0u0);

        herein

            fun adjust_image_data (dy::XDISPLAY dpy_info)
                =
                {
                    fun extra (v, m)
                        =
                        unt::bitwise_and (unt::from_int (w8v::length v), m);

                    pad_scan_line
                        =
                        case dpy_info.bitmap_scanline_pad

                            xt::RAW8
                                =>
                                fn s = s;

                            xt::RAW16
                                =>
                                fn s =
                                    if (extra (s, 0u1) == 0u0)  s;
                                    else                        w8v::cat [s, pad1];
                                    fi;

                            xt::RAW32
                                =>
                                fn s =  case (extra (s, 0u3))
                                            #
                                            0u0 => s;
                                            0u1 => w8v::cat [s, pad3];
                                            0u2 => w8v::cat [s, pad2];
                                            _   => w8v::cat [s, pad1];
                                        esac;


                        esac;

                    swapfn
                        =
                        swap_func
                          (
                            dpy_info.bitmap_scanline_unit,
                            dpy_info.image_byte_order,
                            dpy_info.bitmap_bit_order
                          );

                    fn data
                        =
                        map (fn s = swapfn (pad_scan_line s))
                            data;
                };
        end;

        # Copy rectangle from clientside window
        # into server-side offscreen window.
        #
        # It wouldn't take much to generalize
        # this to all drawables & pens. Additional
        # efficiency could be gained by having the
        # extract_row function extract rows already
        # padded correctly for the display when possible. XXX BUGGO FIXME
        #
        fun copy_from_clientside_pixmap_to_pixmap pm { from=>CS_PIXMAP { size, data }, from_box, to_point }
            =
            {   #  Clip from_box to clientside window:
                #
                from_box' = xg::box::intersection (from_box, xg::box::make (xg::point::zero, size));

                delta
                    =
                    xg::point::subtract
                      ( xg::box::upperleft  from_box',
                        xg::box::upperleft  from_box
                      );

                depth =  list::length data;

                pm  -> dt::RW_PIXMAP { pixmap_id, screen, screen_pen_and_draw_imps => sn::SCREEN_PEN_AND_DRAW_IMPS { to_screen_drawimp, ... }, ... };

                screen -> sn::SCREEN { xsession=>sn::XSESSION { xdisplay as dy::XDISPLAY dpy_info, ... }, ... } ;

                scanline_pad  =  dpy_info.bitmap_scanline_pad;
                scanline_unit =  dpy_info.bitmap_scanline_unit;

                # Minimum no. of 4-byte words needed for PutImage.
                # There should be a function in XRequest to provide this.       XXX BUGGO FIXME
                #
                request_size = 6;

                # Number of image bytes per request:
                #
                available = (int::min (dpy_info.max_request_length, 65536) - request_size) * 4;

                fun copy_from_clientside_pixmap_to_pixmap_request (r as xg::BOX { col, row, wide, high }, to_point)
                    =
                    {
                        left_pad
                            =
                            unt::to_int_x (
                                unt::bitwise_and (unt::from_int col, pad_to_bits scanline_unit - 0u1)
                            );

                        byte_offset = (col - left_pad) / 8;

                        num_bytes   = round_up (wide + left_pad, xt::RAW8) / 8;

                        adjust      = adjust_image_data xdisplay;

                        # Given the list of data for a plane, extract a list of substrings
                        # corresponding to given rectangle, to the nearest byte.
                        #
                        fun extract_box (rows:  List( w8v::Vector ))
                            =
                            {
                                fun skip (0, r) => r;
                                    skip (i, _ ! r) => skip (i - 1, r);
                                    skip (i, []) => xgripe::impossible "cs_pixmap: extract_box (skip)";
                                end;


                                fun extract_row (0, _)
                                        =>
                                        [];

                                    extract_row (i, my_row ! rest)
                                        =>
                                        if (   byte_offset == 0
                                           and num_bytes == w8v::length my_row
                                           )

                                             my_row ! (extract_row (i - 1, rest));
                                        else
                                             (w8vextract (my_row, byte_offset, THE num_bytes))
                                             !
                                             (extract_row (i - 1, rest));
                                        fi;

                                    extract_row (i,[])
                                        =>
                                        xgripe::impossible "cs_pixmap: extract_row";
                                end;

                                extract_row (high, skip (row, rows));
                            };

                        xdata =  map  extract_box  data;

                        to_screen_drawimp
                            (di::d::DRAW
                              {
                                to  => pixmap_id,
                                pen => pen::default_pen,
                                op  => di::o::PUT_IMAGE {
                                    to_point,
                                    size => xg::SIZE { wide, high },
                                    depth,
                                    lpad => left_pad,
                                    format => xt::XYPIXMAP,
          /*** THIS SHOULD BE
                                    data = w8v::cat (list::cat (map adjust xdata))
          ***/
                                    data => w8v::cat (map (w8v::cat o adjust) xdata)
                                  }
                              }
                            );
                      };                                        # fun copy_from_clientside_pixmap_to_pixmap_request

                # Decompose copy_from_clientside_pixmap_to_pixmap
                # into multiple requests smaller than max size.
                #
                # First try to use as many rows as possible;
                # if there is only one row left and it is
                # still too large, decompose by columns:
                #
                fun put_sub_image (r as xg::BOX { col, row, wide, high }, pt as xg::POINT { col=>dx, row=>dy } )
                    =
                    {   left_pad
                            =
                            unt::to_int_x (unt::bitwise_and (unt::from_int col,  pad_to_bits scanline_unit - 0u1));

                        bytes_per_row
                            =
                            (round_up (wide + left_pad, scanline_pad) / 8) * depth;

                        if ((bytes_per_row * high) <= available)
                            #
                            copy_from_clientside_pixmap_to_pixmap_request (r, pt);
                        else
                            if (high > 1)
                                #
                                high' = int::max (1, available / bytes_per_row);

                                put_sub_image (xg::BOX { col, row, wide, high=>high' }, pt);
                                put_sub_image (xg::BOX { col, row=>row+high', wide, high=>high-high' }, xg::POINT { col=>dx, row=>dy+high' } );
                            else
                                wide' = round_down (available * 8, scanline_pad) - left_pad;

                                put_sub_image (xg::BOX { col, row, wide=>wide', high=>1 }, pt);
                                put_sub_image (xg::BOX { col=>col+wide', row, wide=>wide-wide', high=>1 }, xg::POINT { col=>dx+wide', row=>dy } );
                            fi;
                        fi;
                    };

                put_sub_image (from_box', xg::point::add (to_point, delta));

            };                          # fun copy_from_clientside_pixmap_to_pixmap 



        #  Create image data from an ascii representation 
        #
        fun make_clientside_pixmap_from_ascii (wide, p0 ! rest)
                =>
                {   fun mk (n, [],    l) =>   (n, reverse l);
                        mk (n, s ! r, l) =>   mk (n+1, r, string_to_data (wide, s) ! l);
                    end;

                    my (high, plane0)
                        =
                        mk (0, p0, []);

                    fun check data
                        =
                        {   my (h, plane) =   mk (0, data,[]); 

                            if (h == high)    plane;
                            else              raise exception  BAD_CS_PIXMAP_DATA;
                            fi;
                        };

                    CS_PIXMAP {
                        size   =>   xg::SIZE { wide, high },
                        data =>   plane0 ! (map check rest)
                    };
               };

            make_clientside_pixmap_from_ascii (wide, [])
                =>
                raise exception BAD_CS_PIXMAP_DATA;
        end;



        # Create a server-side offscreen window from
        # data in a client-side window:
        #
        fun make_readwrite_pixmap_from_clientside_pixmap
                screen
                (cs_pixmap as CS_PIXMAP { size, data } )
            =
            pixmap
            where
                depth = length data;

                pixmap
                    =
                    wpm::make_readwrite_pixmap
                        screen
                        (size, depth);

                copy_from_clientside_pixmap_to_pixmap
                    pixmap
                    {
                      from     =>  cs_pixmap, 
                      from_box =>  xg::box::make (xg::point::zero, size), 
                      to_point =>  xg::point::zero
                    };
            end;


        # Create an pixmap from ascii data:
        #
        fun make_readwrite_pixmap_from_ascii_data
                screen
                (wide, ascii_rep)
            =
            make_readwrite_pixmap_from_clientside_pixmap
                screen
                (make_clientside_pixmap_from_ascii (wide, ascii_rep));



        stipulate

            # Create a client-side window from
            # a server-side offscreen window.
            #
            # This should be better integrated with
            # the draw_imp to avoid a possible race
            # condition: We need to be sure the
            # draw_imp flush has occurred before we
            # ask for the clientside window.    XXX BUGGO FIXME
            #
            fun make_clientside_pixmap_from_pixmap_or_window
                (
                  box,                                          # Get the pixelmap pixel contents from this part of
                  pixmap_or_window_id as (xt::XID u),           # this server-side pixmap or window.
#                  screen_pen_and_draw_imps,
                  screen
                )
                =
                {   (xg::box::size  box)     ->  size as xg::SIZE our_size;
#                    screen_pen_and_draw_imps ->  sn::SCREEN_PEN_AND_DRAW_IMPS { depth, to_screen_drawimp, ... };

                    (sn::xsession_of_screen  screen)
                        ->
                        sn::XSESSION { xdisplay => dy::XDISPLAY xdisplay, ... };


                    # Avoid a race condition by flushing
                    # from the draw_imp any buffered draw
                    # commands for this drawable before
                    # sending our GetImage request to the
                    # X server:
                    #

# trace  .{ sprintf "XYZZY calling dt::flush_drawimp  -- cs_pixmap::make_clientside_pixmap_from_pixmap_or_window   pixmap_or_window_id x=%x  (drawimp thread_id d=%d)" (unt::to_int u) (dt::drawimp_thread_id_of to_screen_drawimp); };
#                   dt::flush_drawimp  to_screen_drawimp;
# trace  .{ sprintf "XYZZY done    dt::flush_drawimp  -- cs_pixmap::make_clientside_pixmap_from_pixmap_or_window   pixmap_or_window_id x=%x  (drawimp thread_id d=%d)" (unt::to_int u) (dt::drawimp_thread_id_of to_screen_drawimp); };

                    all_planes = unt::bitwise_not 0u0;

                    msg =   v2w::encode_get_image
                              { 
                                drawable   =>  pixmap_or_window_id, 
                                box,
                                plane_mask =>  xt::PLANEMASK all_planes, 
                                format     =>  xt::XYPIXMAP
                              };
trace  .{ sprintf "XYZZY calling GetImage, string == %s -- cs_pixmap::make_clientside_pixmap_from_pixmap_or_window" (xok::bytes_to_hex msg); };

                    my { depth, data, visualid }
                        = 
                        w2v::decode_get_image_reply
                            (
                            do_mailop
                                (
                                xok::send_xrequest_and_read_reply  xdisplay.xsocket  msg
                                )
                            );
trace  .{ sprintf "XYZZY done    GetImage, string == %s -- cs_pixmap::make_clientside_pixmap_from_pixmap_or_window" (xok::bytes_to_hex msg); };

                    swapfn
                        =
                        swap_func
                          (
                            xdisplay.bitmap_scanline_unit,
                            xdisplay.image_byte_order,
                            xdisplay.bitmap_bit_order
                          );

                    lines_per_plane = our_size.high;

                    bytes_per_line  = round_up (our_size.wide, xdisplay.bitmap_scanline_pad) / 8;
                    bytes_per_plane = bytes_per_line * lines_per_plane;

                    fun do_line start
                        =
                        swapfn (w8vextract (data, start, THE bytes_per_line));

                    fun make_line (i, start)
                        =
                        i == lines_per_plane
                         ?? []
                         :: (do_line start) ! (make_line (i+1, start+bytes_per_line));

                    fun make_plane (i, start)
                        =
                        i == depth
                         ?? []
                         :: (make_line (0, start)) ! (make_plane (i+1, start+bytes_per_plane));

                    CS_PIXMAP { size, data=>make_plane (0, 0) };
                };                                              # fun make_clientside_pixmap_from_pixmap_or_window

        herein

            # Create a client-side window from
            # a server-side offscreen window.
            #
            fun make_clientside_pixmap_from_readwrite_pixmap (dt::RW_PIXMAP { pixmap_id, size, screen, screen_pen_and_draw_imps } )
                =
                {   # Before attempting to read back pixels
                    # from the X server we want to be sure that
                    # any relevant draw commands have been flushed
                    # from the relevant draw-imp.  For a RW_PIXMAP
                    # that means to_screen_drawimp:
                    #
                    screen_pen_and_draw_imps ->  sn::SCREEN_PEN_AND_DRAW_IMPS { to_screen_drawimp, ... };
                    dt::flush_drawimp  to_screen_drawimp;

                    box = xg::box::make (xg::point::zero, size);        # Copy all of pixmap.
                    #
                    make_clientside_pixmap_from_pixmap_or_window (box, pixmap_id, screen);
                };

            # Create a client-side window from part of
            # a server-side onscreen window.  The underlying
            # GetImage X call is snarky:
            #
            #   o The window must be entirely onscreen.
            #   o Any parts of it obscured by non-descendents      come back undefined.
            #   o Any parts of it obscured by different-depth kids come back undefined.
            #
            # According to he docs on p57 of http://mythryl.org/pub/exene/X-protocol-R6.pdf
            #
            #    "This request is not general-purpose in the same sense
            #     as other graphics-related requests.  It is intended
            #     specifically for rudimentary hardcopy support." 
            #
            fun make_clientside_pixmap_from_window (box, window as dt::WINDOW { window_id, screen, to_topwindow_drawimp, ... } )
                =
                {   # Before attempting to read back pixels
                    # from the X server we want to be sure that
                    # any relevant draw commands have been flushed
                    # from the relevant draw-imp.  For a WINDOW
                    # that means to_topwindow_drawimp:
                    #
                    dt::flush_drawimp  to_topwindow_drawimp;

# screen_pen_and_draw_imps   -> sn::SCREEN_PEN_AND_DRAW_IMPS { depth, to_screen_drawimp, ... };
# trace .{ sprintf "XYZZY make_clientside_pixmap_from_window: window.id x=%x   drawimp_thread_id_of window d=%d SCREEN_PEN_AND_DRAW_IMPS.to_screen_drawimp.thread_id d=%d" (dt::id_of_window window) (draw::drawimp_thread_id_of (dt::drawable_of_window  window)) (dt::drawimp_thread_id_of to_screen_drawimp); };
                    make_clientside_pixmap_from_pixmap_or_window    (box, window_id, screen);
                };

        end;

        fun make_clientside_pixmap_from_readonly_pixmap (dt::RO_PIXMAP pm)
            =
            make_clientside_pixmap_from_readwrite_pixmap   pm;

    };                                                                  # package cs_pixmap

end;


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext