## cs-pixmap-old.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/src/window/ro-pixmap-old.pkg#
src/lib/x-kit/xclient/src/window/window-old.pkg#
src/lib/x-kit/xclient/src/window/rw-pixmap-old.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 package 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_old; # draw_imp_old is from
src/lib/x-kit/xclient/src/window/draw-imp-old.pkg package dt = draw_types_old; # draw_types_old is from
src/lib/x-kit/xclient/src/window/draw-types-old.pkg package dy = display_old; # display_old is from
src/lib/x-kit/xclient/src/wire/display-old.pkg package g2d = geometry2d; # geometry2d is from
src/lib/std/2d/geometry2d.pkg package sn = xsession_old; # xsession_old is from
src/lib/x-kit/xclient/src/window/xsession-old.pkg package w2v = wire_to_value; # wire_to_value is from
src/lib/x-kit/xclient/src/wire/wire-to-value.pkg package wpm = rw_pixmap_old; # rw_pixmap_old is from
src/lib/x-kit/xclient/src/window/rw-pixmap-old.pkg package v2w = value_to_wire; # value_to_wire is from
src/lib/x-kit/xclient/src/wire/value-to-wire.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 package pn = pen_old; # pen_old is from
src/lib/x-kit/xclient/src/window/pen-old.pkg #
trace = xtr::log_if xtr::io_logging 0; # Conditionally write strings to tracing.log or whatever.
herein
package cs_pixmap_old
: (weak) Cs_Pixmap_Old
{
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_Old
=
CS_PIXMAP
{ size: g2d::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 (g2d::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 "\
\\x00\x80\x40\xc0\x20\xa0\x60\xe0\
\\x10\x90\x50\xd0\x30\xb0\x70\xf0\
\\x08\x88\x48\xc8\x28\xa8\x68\xe8\
\\x18\x98\x58\xd8\x38\xb8\x78\xf8\
\\x04\x84\x44\xc4\x24\xa4\x64\xe4\
\\x14\x94\x54\xd4\x34\xb4\x74\xf4\
\\x0c\x8c\x4c\xcc\x2c\xac\x6c\xec\
\\x1c\x9c\x5c\xdc\x3c\xbc\x7c\xfc\
\\x02\x82\x42\xc2\x22\xa2\x62\xe2\
\\x12\x92\x52\xd2\x32\xb2\x72\xf2\
\\x0a\x8a\x4a\xca\x2a\xaa\x6a\xea\
\\x1a\x9a\x5a\xda\x3a\xba\x7a\xfa\
\\x06\x86\x46\xc6\x26\xa6\x66\xe6\
\\x16\x96\x56\xd6\x36\xb6\x76\xf6\
\\x0e\x8e\x4e\xce\x2e\xae\x6e\xee\
\\x1e\x9e\x5e\xde\x3e\xbe\x7e\xfe\
\\x01\x81\x41\xc1\x21\xa1\x61\xe1\
\\x11\x91\x51\xd1\x31\xb1\x71\xf1\
\\x09\x89\x49\xc9\x29\xa9\x69\xe9\
\\x19\x99\x59\xd9\x39\xb9\x79\xf9\
\\x05\x85\x45\xc5\x25\xa5\x65\xe5\
\\x15\x95\x55\xd5\x35\xb5\x75\xf5\
\\x0d\x8d\x4d\xcd\x2d\xad\x6d\xed\
\\x1d\x9d\x5d\xdd\x3d\xbd\x7d\xfd\
\\x03\x83\x43\xc3\x23\xa3\x63\xe3\
\\x13\x93\x53\xd3\x33\xb3\x73\xf3\
\\x0b\x8b\x4b\xcb\x2b\xab\x6b\xeb\
\\x1b\x9b\x5b\xdb\x3b\xbb\x7b\xfb\
\\x07\x87\x47\xc7\x27\xa7\x67\xe7\
\\x17\x97\x57\xd7\x37\xb7\x77\xf7\
\\x0f\x8f\x4f\xcf\x2f\xaf\x6f\xef\
\\x1f\x9f\x5f\xdf\x3f\xbf\x7f\xff";
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_backward (\\ (b, l) = rev_bits b ! l) [] data);
fun explode_v data
=
w8v::fold_backward (!) [] 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::RAW08, 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::RAW08, 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::RAW08, 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::RAW08, 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::RAW08 => 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::from_fn (1, \\ _ = 0u0);
pad2 = w8v::from_fn (2, \\ _ = 0u0);
pad3 = w8v::from_fn (3, \\ _ = 0u0);
herein
fun adjust_image_data (dpy_info: dy::Xdisplay)
=
{
fun extra (v, m)
=
unt::bitwise_and (unt::from_int (w8v::length v), m);
pad_scan_line
=
case dpy_info.bitmap_scanline_pad
#
xt::RAW08
=>
\\ s = s;
xt::RAW16
=>
\\ s =
if (extra (s, 0u1) == 0u0) s;
else w8v::cat [s, pad1];
fi;
xt::RAW32
=>
\\ 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
);
\\ data
=
map (\\ 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 }
=
case (g2d::box::intersection (from_box, g2d::box::make (g2d::point::zero, size))) # Clip from_box to clientside window.
#
NULL => (); # No intersection so nothing to do.
#
THE from_box'
=>
{ delta = g2d::point::subtract
(
g2d::box::upperleft from_box',
g2d::box::upperleft from_box
);
depth = list::length data;
pm -> { pixmap_id, screen, per_depth_imps => { to_screen_drawimp, ... }: sn::Per_Depth_Imps, ... }: dt::Rw_Pixmap;
screen -> { xsession=>{ xdisplay as (dpy_info: dy::Xdisplay), ... }: sn::Xsession, ... }: sn::Screen ;
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 { 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::RAW08) / 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_old: 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_old: extract_row";
end;
extract_row (high, skip (row, rows));
};
xdata = map extract_box data;
to_screen_drawimp
(di::d::DRAW
{
to => pixmap_id,
pen => pn::default_pen,
op => di::o::PUT_IMAGE {
to_point,
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 { col, row, wide, high }, pt as { 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 ({ col, row, wide, high=>high' }, pt);
put_sub_image ({ col, row=>row+high', wide, high=>high-high' }, { col=>dx, row=>dy+high' } );
else
wide' = round_down (available * 8, scanline_pad) - left_pad;
put_sub_image ({ col, row, wide=>wide', high=>1 }, pt);
put_sub_image ({ col=>col+wide', row, wide=>wide-wide', high=>1 }, { col=>dx+wide', row=>dy } );
fi;
fi;
};
put_sub_image (from_box', g2d::point::add (to_point, delta));
}; # fun copy_from_clientside_pixmap_to_pixmap
esac;
# 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 => { 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_old 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_old,
from_box => g2d::box::make (g2d::point::zero, size),
to_point => g2d::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 xid, # this server-side pixmap or window.
# per_depth_imps,
screen
)
=
{ (g2d::box::size box) -> size as our_size;
# per_depth_imps -> { depth, to_screen_drawimp, ... }: sn::Per_Depth_Imps;
(sn::xsession_of_screen screen)
->
{ xdisplay, ... }: sn::Xsession;
# 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_old::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_old::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_old::make_clientside_pixmap_from_pixmap_or_window" (xok::bytes_to_hex msg); };
my { depth, data, visualid }
=
w2v::decode_get_image_reply
(
block_until_mailop_fires
(
xok::send_xrequest_and_read_reply xdisplay.xsocket msg
)
);
trace {. sprintf "XYZZY done GetImage, string == %s -- cs_pixmap_old::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 ({ pixmap_id, size, screen, per_depth_imps }: dt::Rw_Pixmap)
=
{ # 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:
#
per_depth_imps -> { to_screen_drawimp, ... }: sn::Per_Depth_Imps;
dt::flush_drawimp to_screen_drawimp;
box = g2d::box::make (g2d::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 { window_id, screen, to_hostwindow_drawimp, ... }: dt::Window )
=
{ # 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_hostwindow_drawimp:
#
dt::flush_drawimp to_hostwindow_drawimp;
# per_depth_imps -> { depth, to_screen_drawimp, ... }: sn::Per_Depth_Imps;
# trace {. sprintf "XYZZY make_clientside_pixmap_from_window: window.id x=%x drawimp_thread_id_of window d=%d PER_DEPTH_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_old
end;