## cs-pixmat.pkg "cs" == "client-side"
#
# A replacement for
src/lib/x-kit/xclient/src/window/cs-pixmap.pkg#
# 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 SUCKO 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 byt = byte; # byte is from
src/lib/std/src/byte.pkg package mtx = rw_matrix; # rw_matrix is from
src/lib/std/src/rw-matrix.pkg package r8 = rgb8; # rgb8 is from
src/lib/x-kit/xclient/src/color/rgb8.pkg package s1u = vector_slice_of_one_byte_unts; # vector_slice_of_one_byte_unts is from
src/lib/std/src/vector-slice-of-one-byte-unts.pkg package u1b = one_byte_unt; # one_byte_unt is from
src/lib/std/one-byte-unt.pkg package v1u = vector_of_one_byte_unts; # vector_of_one_byte_unts is from
src/lib/std/src/vector-of-one-byte-unts.pkg package v2w = value_to_wire; # value_to_wire is from
src/lib/x-kit/xclient/src/wire/value-to-wire.pkg package w2v = wire_to_value; # wire_to_value is from
src/lib/x-kit/xclient/src/wire/wire-to-value.pkg package w8 = one_byte_unt; # one_byte_unt is from
src/lib/std/one-byte-unt.pkg package g2d = geometry2d; # geometry2d is from
src/lib/std/2d/geometry2d.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 di = xserver_ximp; # xserver_ximp is from
src/lib/x-kit/xclient/src/window/xserver-ximp.pkg# package dt = draw_types; # draw_types is from
src/lib/x-kit/xclient/src/window/draw-types.pkg package dy = display; # display is from
src/lib/x-kit/xclient/src/wire/display.pkg package w2x = windowsystem_to_xserver; # windowsystem_to_xserver is from
src/lib/x-kit/xclient/src/window/windowsystem-to-xserver.pkg package pn = pen; # pen is from
src/lib/x-kit/xclient/src/window/pen.pkg package xj = xsession_junk; # xsession_junk is from
src/lib/x-kit/xclient/src/window/xsession-junk.pkg# package x2s = xclient_to_sequencer; # xclient_to_sequencer is from
src/lib/x-kit/xclient/src/wire/xclient-to-sequencer.pkg package wpm = rw_pixmap; # rw_pixmap is from
src/lib/x-kit/xclient/src/window/rw-pixmap.pkg #
trace = xtr::log_if xtr::io_logging 0; # Conditionally write strings to tracing.log or whatever.
herein
package cs_pixmat
: (weak) Cs_Pixmat # Cs_Pixmat is from
src/lib/x-kit/xclient/src/window/cs-pixmat.api {
exception BAD_CS_PIXMAT_DATA;
v1uextract = s1u::to_vector
o
s1u::make_slice;
Cs_Pixmat = CS_PIXMAT { size: g2d::Size,
data: v1u::Vector
};
# Two cs_pixmats are the same
# iff their fields are the same:
#
fun same_cs_pixmat
( CS_PIXMAT { size => size1, data => data1 },
CS_PIXMAT { size => size2, data => data2 }
)
=
if (not (g2d::size::eq (size1, size2)))
#
FALSE;
else
data1 == data2;
fi;
#
fun string_to_data (wid, s) # Map a row of data coded as a string to a bit representation.
= # The data may be either encoded in hex (with a preceding "0x")
case (string::explode s) # or in binary (with a preceeding "0b").
#
('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_PIXMAT_DATA;
fi;
fi;
fun make_row (0, [], l) => v1u::from_list (reverse l);
make_row (0, _, _) => raise exception BAD_CS_PIXMAT_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_PIXMAT_DATA;
end;
end;
('0' ! 'b' ! r)
=>
make_row (wid, 0ux80, r, 0u0, [])
where
fun make_row (0, _, [], b, l)
=>
v1u::from_list (reverse (b ! l));
make_row (_, _, [], _, _)
=>
raise exception BAD_CS_PIXMAT_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_PIXMAT_DATA;
end;
end;
_ => raise exception BAD_CS_PIXMAT_DATA;
esac;
reverse_bits = byt::reverse_byte_bits; # Reverse the bit-order of a byte
# 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
=
v1u::from_list
(v1u::fold_backward (\\ (b, l) = reverse_bits b ! l)
[]
data
);
fun explode_v data
=
v1u::fold_backward (!) [] data;
fun swap_two_bytes s
=
v1u::from_list (swap (explode_v s))
where
fun swap (a ! b ! r) => b ! a ! (swap r);
swap [] => [];
swap _ => xgripe::impossible "[swap_two_bytes: bad image data]";
end;
end;
fun swap_four_bytes s
=
v1u::from_list (swap (explode_v s))
where
fun swap (a ! b ! c ! d ! r) => d ! c ! b ! a ! (swap r);
swap [] => [];
swap _ => xgripe::impossible "[swap_four_bytes: bad image data]";
end;
end;
fun swap_bits_and_two_bytes s
=
v1u::from_list (swap (explode_v s))
where
fun swap (a ! b ! r) => (reverse_bits b) ! (reverse_bits a) ! (swap r);
swap [] => [];
swap _ => xgripe::impossible "[swap_bits_and_two_bytes: bad image data]";
end;
end;
fun swap_bits_and_four_bytes s
=
v1u::from_list (swap (explode_v s))
where
fun swap (a ! b ! c ! d ! r)
=>
(reverse_bits d) ! (reverse_bits c) ! (reverse_bits b) ! (reverse_bits a) ! (swap r);
swap [] => [];
swap _ => xgripe::impossible "[swap_bits_and_four_bytes: bad image data]";
end;
end;
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 = v1u::from_fn (1, \\ _ = 0u0);
pad2 = v1u::from_fn (2, \\ _ = 0u0);
pad3 = v1u::from_fn (3, \\ _ = 0u0);
#
herein
#
fun adjust_image_data (dpy_info: dy::Xdisplay)
=
{
fun extra (v, m)
=
unt::bitwise_and (unt::from_int (v1u::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 v1u::cat [s, pad1];
fi;
xt::RAW32
=>
\\ s = case (extra (s, 0u3))
#
0u0 => s;
0u1 => v1u::cat [s, pad3];
0u2 => v1u::cat [s, pad2];
_ => v1u::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 SUCKO FIXME
#
fun make_clientside_pixmat_to_pixmap_copy_drawop
#
(to: xt::Window_Id) # This will currently be either window.window_id or (the window.subwindow_or_view).
# (window: xj::Window)
(dpy_info: dy::Xdisplay)
# (pixmap_id: xt::Window_Id) # Maybe should be xt::Drawable_Id? They are both just defined as Xid though.
#
# (screen: xj::Screen)
#
{ from => (m as { rw_vector, rows, cols }): mtx::Rw_Matrix( r8::Rgb8 ), from_box, to_point }
=
case (g2d::box::intersection (from_box, g2d::box::make (g2d::point::zero, { wide => cols, high => rows }))) # Clip from_box to clientside window:
#
NULL => []; # No intersection so nothing to do.
#
THE from_box'
=>
{ ops = put_sub_image (from_box', g2d::point::add (to_point, delta));
#
[ { to,
pen => pn::default_pen,
op => w2x::x::PUT_IMAGE ops
}
];
}
where
delta = g2d::point::subtract
( g2d::box::upperleft from_box',
g2d::box::upperleft from_box
);
depth = 24; # XXX SUCKO FIXME should be deriving this from xserver_info or visual or screen or such.
bytes_per_pixel = 4; # XXX SUCKO FIXME should be deriving this from xserver_info or visual or screen or such.
# Minimum no. of 4-byte words needed for PutImage.
# There should be a function in XRequest to provide this. XXX SUCKO 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_pixmat_to_pixmap_request (r as { col, row, wide, high }, to_point)
=
{
pixels_to_send = wide * high;
bytes_to_send = pixels_to_send * bytes_per_pixel;
vectors_to_send = REF ([]: List(v1u::Vector)); # This isn't terribly efficient; we should have a PUT_IMAGE that takes rw_vectors, or build in a rw_vector and convert to vector or something. All in good time.
fun note vec
=
vectors_to_send := vec ! *vectors_to_send;
fun col_lup (r, c)
=
if (c == wide) ();
else
(r8::rgb8_to_ints m[row+r,col+c]) -> (red, green, blue);
note (v1u::from_list (map u1b::from_int [ blue, green, red, 0 ]));
col_lup (r, c+1);
fi;
fun row_lup r
=
if (r == high) ();
else col_lup (r, 0);
row_lup (r+1);
fi;
row_lup 0;
data = v1u::cat (reverse *vectors_to_send);
[ { to_point,
size => { wide, high },
depth,
lpad => 0,
format => xt::ZPIXMAP,
data
}
];
}; # fun copy_from_clientside_pixmat_to_pixmap_request
# Decompose copy_from_clientside_pixmat_to_pixmap
# into multiple requests smaller than max size.
#
# I'm ignoring the possiblity that the X server # Current xorg server max request size is 64K bytes.
# max request size might be too small to accept # A 5000 pixel wide monitor at 4 bytes/pixel yields 20KB/row.
# a single row of pixels:
#
fun put_sub_image (r as { col, row, wide, high }, pt as { col=>dx, row=>dy } )
=
{ left_pad = 0;
#
bytes_per_row = 4 * wide;
if ((bytes_per_row * high) <= available)
#
copy_from_clientside_pixmat_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
put_sub_image ({ col, row, wide, high=>1 }, pt);
fi;
fi;
};
end; # fun copy_from_clientside_pixmat_to_pixmap
esac;
fun copy_from_clientside_pixmat_to_pixmap
#
(window: xj::Window)
#
(arg as { from => (m as { rw_vector, rows, cols }): mtx::Rw_Matrix( r8::Rgb8 ), from_box, to_point })
=
window.windowsystem_to_xserver.draw_ops
(
make_clientside_pixmat_to_pixmap_copy_drawop
window.window_id
window.screen.xsession.xdisplay
arg
);
# # Create image data from an ascii representation
# #
# fun make_clientside_pixmat_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;
#
# (mk (0, p0, []))
# ->
# (high, plane0);
#
# fun check data
# =
# { (mk (0, data,[]))
# ->
# (h, plane);
#
# if (h == high) plane;
# else raise exception BAD_CS_PIXMAT_DATA;
# fi;
# };
#
# CS_PIXMAT {
# size => { wide, high },
# data => plane0 ! (map check rest)
# };
# };
#
# make_clientside_pixmat_from_ascii (wide, [])
# =>
# raise exception BAD_CS_PIXMAT_DATA;
# end;
# Create a server-side offscreen window from
# data in a client-side window:
#
# fun make_readwrite_pixmap_from_clientside_pixmat
# screen
# (cs_pixmat_old as CS_PIXMAT { size, data } )
# =
# pixmap
# where
# depth = length data;
#
# pixmap
# =
# wpm::make_readwrite_pixmap
# screen
# (size, depth);
#
# copy_from_clientside_pixmat_to_pixmap
# pixmap
# {
# from => cs_pixmat_old,
# from_box => g2d::box::make (g2d::point::zero, size),
# to_point => g2d::point::zero
# };
# end;
# Create a pixmap from ascii data:
#
# fun make_readwrite_pixmap_from_ascii_data
# screen
# (wide, ascii_rep)
# =
# make_readwrite_pixmap_from_clientside_pixmat
# screen
# (make_clientside_pixmat_from_ascii (wide, ascii_rep));
# rgb8.pkg encodes as:
# red = 0xFF0000
# green = 0x00FF00
# blue = 0x0000FF
#
# In xclient-unit-test.pgk we set
# background_pixel = r8::rgb8_from_ints (128+64, 1, 255);
#
# and it reads back as 512 bytes looking so:
#
# FF.01.C0.00. FF.01.C0.00. FF.01.C0.00. FF.01.C0.00. ...
# so
stipulate
fun make_clientside_pixmat_from_pixmap_or_window'
(
box, # Get the pixelmap pixel contents from this part of
pixmap_or_window_id, # this server-side pixmap or window.
screen,
reply_image
)
=
{ image = w2v::decode_get_image_reply reply_image;
#
(g2d::box::size box) -> our_size;
(xj::xsession_of_screen screen)
->
{ xdisplay, windowsystem_to_xserver, ... }: xj::Xsession;
image -> { depth, data, visualid };
swapfn = swap_func
(
xdisplay.bitmap_scanline_unit,
xdisplay.image_byte_order,
xdisplay.bitmap_bit_order
);
lines = 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 (v1uextract (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));
bytes_per_pixel = 4; # XXX SUCKO FIXME We should be prying this out of xserver_info or such.
expected_bytes = our_size.high * our_size.wide * bytes_per_pixel;
actual_bytes = v1u::length data;
if (actual_bytes != expected_bytes)
#
msg = (sprintf "make_clientside_pixmat_from_pixmap_or_window: Expected read of (%d rows, %d cols) to produce %d bytes but got %d instead."
our_size.high our_size.wide expected_bytes actual_bytes
);
log::fatal msg;
raise exception DIE msg; # Shouldn't get here, but compiler doesn't know that log::fatal doesn't return.
fi;
m = mtx::make_rw_matrix ((our_size.high, our_size.wide), r8::rgb8_black);
d = (data: v1u::Vector);
for (i = 0, row = 0, col = 0; i < actual_bytes; i = i + 4) {
#
blue = u1b::to_int (d[ i+0 ]);
green = u1b::to_int (d[ i+1 ]);
red = u1b::to_int (d[ i+2 ]);
rgb8 = r8::rgb8_from_ints (red, green, blue);
m[row,col] := rgb8;
my (row, col) = if (col < our_size.wide - 1) (row, col+1);
else (row+1, 0);
fi;
};
m;
};
# Create a client-side pixmat from
# a server-side offscreen window.
#
fun make_clientside_pixmat_from_pixmap_or_window
(
box, # Get the pixelmap pixel contents from this part of
pixmap_or_window_id, # this server-side pixmap or window.
screen
)
=
{ (xj::xsession_of_screen screen)
->
{ windowsystem_to_xserver, ... }: xj::Xsession;
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::ZPIXMAP
};
reply_image
=
block_until_mailop_fires # XXX SUCKO FIXME
# ========================
(
windowsystem_to_xserver.xclient_to_sequencer.send_xrequest_and_read_reply msg #
src/lib/x-kit/xclient/src/wire/xclient-to-sequencer.pkg );
make_clientside_pixmat_from_pixmap_or_window'
(
box, # Get the pixelmap pixel contents from this part of
pixmap_or_window_id, # this server-side pixmap or window.
screen,
reply_image
);
}; # fun make_clientside_pixmat_from_pixmap_or_window
# Same as above, done nonblocking for imps:
#
fun pass_clientside_pixmat_from_pixmap_or_window
(
box, # Get the pixelmap pixel contents from this part of
pixmap_or_window_id, # this server-side pixmap or window.
screen,
(to: Replyqueue),
(sink_fn: (mtx::Rw_Matrix( r8::Rgb8 ) -> Void))
)
=
{ (xj::xsession_of_screen screen)
->
{ windowsystem_to_xserver, ... }: xj::Xsession;
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::ZPIXMAP
};
windowsystem_to_xserver.xclient_to_sequencer.send_xrequest_and_pass_reply #
src/lib/x-kit/xclient/src/wire/xclient-to-sequencer.pkg #
msg
to
(\\ reply_image
=
{ rw_matrix
=
make_clientside_pixmat_from_pixmap_or_window'
(
box, # Get the pixelmap pixel contents from this part of
pixmap_or_window_id, # this server-side pixmap or window.
screen,
reply_image
);
sink_fn rw_matrix;
}
);
}; # fun make_clientside_pixmat_from_pixmap_or_window
herein
# Create a client-side window from
# a server-side offscreen window.
#
fun make_clientside_pixmat_from_readwrite_pixmap
#
( box: g2d::Box,
{ pixmap_id, size, screen, per_depth_imps }: xj::Rw_Pixmap
)
=
{
# box = g2d::box::make (g2d::point::zero, size); # Copy all of pixmap.
#
make_clientside_pixmat_from_pixmap_or_window (box, pixmap_id, screen);
};
# Same as above, done nonblocking for imps:
#
fun pass_clientside_pixmat_from_readwrite_pixmap
#
( box: g2d::Box,
{ pixmap_id, size, screen, per_depth_imps }: xj::Rw_Pixmap
)
(to: Replyqueue)
(sink_fn: (mtx::Rw_Matrix( r8::Rgb8 ) -> Void))
=
{
# box = g2d::box::make (g2d::point::zero, size); # Copy all of pixmap.
#
pass_clientside_pixmat_from_pixmap_or_window (box, pixmap_id, screen, to, sink_fn);
};
# 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 the 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_pixmat_from_window
#
(box, window as { window_id, screen, windowsystem_to_xserver, ... }: xj::Window)
=
{
make_clientside_pixmat_from_pixmap_or_window (box, window_id, screen);
};
# Same as above, done nonblocking for imps:
#
fun pass_clientside_pixmat_from_window
#
(box, window as { window_id, screen, windowsystem_to_xserver, ... }: xj::Window)
(to: Replyqueue)
(sink_fn: (mtx::Rw_Matrix( r8::Rgb8 ) -> Void))
=
{
pass_clientside_pixmat_from_pixmap_or_window (box, window_id, screen, to, sink_fn);
};
end;
fun make_clientside_pixmat_from_readonly_pixmap (box: g2d::Box, xj::RO_PIXMAP pm)
=
make_clientside_pixmat_from_readwrite_pixmap (box, pm);
# Same as above, done nonblocking for imps:
#
fun pass_clientside_pixmat_from_readonly_pixmap (box: g2d::Box, xj::RO_PIXMAP pm)
=
pass_clientside_pixmat_from_readwrite_pixmap (box, pm);
}; # package cs_pixmat_old
end;
########################################################################################################
# Note[1]: XYPIXMAP vs ZPIXMAP image interchange with the X server.
#
# From http://mythryl.org/pub/exene/X-protocol-R6.pdf
#
# PutImage: The left-pad must be zero for ZPixmap format (or a Match error results).
# The width argument defines the width of the actual image and does not include left-pad.
#
# GetImage: If ZPixmap is specified, then bits in all planes not specified in plane-mask are transmitted as zero.
# The returned depth is as specified when the drawable was created and is the same as a depth component in a FORMAT structure (in the connection setup), not a bits-per-pixel component.
#
# NB: On my xorg x86 Linux we have
# image_byte_order s= LEAST_SIGNIFICANT_BYTE_FIRST
# bitmap_order s= LEAST_SIGNIFICANT_BIT_FIRST
# (so XYNORMALIZE and ZNORMALIZE are no-ops)
# bitmap_scanline_unit s= 32 bits
# bitmap_scanline_pad s= 32 bits
# and the visuals I see actually in use all look like
# depth d=24
# colormap entries d=256
# colorbits_per_rgb d=8
# red_mask x=00ff0000
# green_mask x=0000ff00
# blue_mask x=000000ff
# display_class s=TRUE_COLOR
#
# In practice, the best documentation of this stuff appears to be the
# xlib source code, so I'm excerpting here the parts relevant to
# processing XYPIXMAP vs ZPIXMAP images:
#
# From /mit/lib/X/XImUtil.c
# * The ROUNDUP macro rounds up a quantity to the specified boundary,
# * then truncates to bytes.
# *
# * The XYNORMALIZE macro determines whether XY format data requires
# * normalization and calls a routine to do so if needed. The logic in
# * this module is designed for LSBFirst byte and bit order, so
# * normalization is done as required to present the data in this order.
# *
# * The ZNORMALIZE macro performs byte and nibble order normalization if
# * required for Z format data.
# *
# * The XYINDEX macro computes the index to the starting byte (char) boundary
# * for a bitmap_unit containing a pixel with coordinates x and y for image
# * data in XY format.
# *
# * The ZINDEX macro computes the index to the starting byte (char) boundary
# * for a pixel with coordinates x and y for image data in ZPixmap format.
# *
# */
#
# #define ROUNDUP(nbytes, pad) ((((nbytes) + ((pad)-1)) / (pad)) * ((pad)>>3))
#
# #define XYNORMALIZE(bp, img) \
# if ((img->byte_order == MSBFirst)
|| (img->bitmap_bit_order == MSBFirst)) \
# _xynormalizeimagebits((unsigned char *)(bp), img)
#
# #define ZNORMALIZE(bp, img) \
# if (img->byte_order == MSBFirst) \
# _znormalizeimagebits((unsigned char *)(bp), img)
#
# #define XYINDEX(x, y, img) \
# ((y) * img->bytes_per_line) + \
# (((x) + img->xoffset) / img->bitmap_unit) * (img->bitmap_unit >> 3)
#
# #define ZINDEX(x, y, img) ((y) * img->bytes_per_line) + \
# (((x) * img->bits_per_pixel) >> 3)
#
#
# if (format == ZPixmap)
# image->bytes_per_line =
# ROUNDUP((bits_per_pixel * width), image->bitmap_pad);
# else
# image->bytes_per_line =
# ROUNDUP((width + offset), image->bitmap_pad);
# /*
# * GetPixel
# *
# * Returns the specified pixel. The X and Y coordinates are relative to
# * the origin (upper left [0,0]) of the image. The pixel value is returned
# * in normalized format, i.e. the LSB of the long is the LSB of the pixel.
# * The algorithm used is:
# *
# * copy the source bitmap_unit or Zpixel into temp
# * normalize temp if needed
# * extract the pixel bits into return value
# *
# */
#
# static unsigned long Const low_bits_table[] = {
# 0x00000000, 0x00000001, 0x00000003, 0x00000007,
# 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
# 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
# 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
# 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
# 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
# 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
# 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
# 0xffffffff
# };
#
# static unsigned long _XGetPixel (ximage, x, y)
# register XImage *ximage;
# int x;
# int y;
#
# {
# unsigned long pixel, px;
# register char *src;
# register char *dst;
# register int i, j;
# int bits, nbytes;
# long plane;
#
# if (ximage->depth == 1) {
# src = &ximage->data[XYINDEX(x, y, ximage)];
# dst = (char *)&pixel;
# pixel = 0;
# for (i = ximage->bitmap_unit >> 3; --i >= 0; ) *dst++ = *src++;
# XYNORMALIZE(&pixel, ximage);
# bits = (x + ximage->xoffset) % ximage->bitmap_unit;
# pixel = ((((char *)&pixel)[bits>>3])>>(bits&7)) & 1;
# } else if (ximage->format == XYPixmap) {
# pixel = 0;
# plane = 0;
# nbytes = ximage->bitmap_unit >> 3;
# for (i = ximage->depth; --i >= 0; ) {
# src = &ximage->data[XYINDEX(x, y, ximage)+ plane];
# dst = (char *)&px;
# px = 0;
# for (j = nbytes; --j >= 0; ) *dst++ = *src++;
# XYNORMALIZE(&px, ximage);
# bits = (x + ximage->xoffset) % ximage->bitmap_unit;
# pixel = (pixel << 1)
|
# (((((char *)&px)[bits>>3])>>(bits&7)) & 1);
# plane = plane + (ximage->bytes_per_line * ximage->height);
# }
# } else if (ximage->format == ZPixmap) {
# src = &ximage->data[ZINDEX(x, y, ximage)];
# dst = (char *)&px;
# px = 0;
# for (i = (ximage->bits_per_pixel + 7) >> 3; --i >= 0; )
# *dst++ = *src++;
# ZNORMALIZE(&px, ximage);
# pixel = 0;
# for (i=sizeof(unsigned long); --i >= 0; )
# pixel = (pixel << 8)
| ((unsigned char *)&px)[i];
# if (ximage->bits_per_pixel == 4) {
# if (x & 1)
# pixel >>= 4;
# else
# pixel &= 0xf;
# }
# } else {
# return 0; /* bad image */
# }
# if (ximage->bits_per_pixel == ximage->depth)
# return pixel;
# else
# return (pixel & low_bits_table[ximage->depth]);
# }
#
# /*
# * This module provides rudimentary manipulation routines for image data
# * structures. The functions provided are:
# *
# * XCreateImage Creates a default XImage data structure
# * _XDestroyImage Deletes an XImage data structure
# * _XGetPixel Reads a pixel from an image data structure
# * _XGetPixel32 Reads a pixel from a 32-bit Z image data structure
# * _XGetPixel16 Reads a pixel from a 16-bit Z image data structure
# * _XGetPixel8 Reads a pixel from an 8-bit Z image data structure
# * _XGetPixel1 Reads a pixel from an 1-bit image data structure
# * _XPutPixel Writes a pixel into an image data structure
# * _XPutPixel32 Writes a pixel into a 32-bit Z image data structure
# * _XPutPixel16 Writes a pixel into a 16-bit Z image data structure
# * _XPutPixel8 Writes a pixel into an 8-bit Z image data structure
# * _XPutPixel1 Writes a pixel into an 1-bit image data structure
# * _XSubImage Clones a new (sub)image from an existing one
# * _XSetImage Writes an image data pattern into another image
# * _XAddPixel Adds a constant value to every pixel in an image
# *
# * The logic contained in these routines makes several assumptions about
# * the image data structures, and at least for current implementations
# * these assumptions are believed to be true. They are:
# *
# * For all formats, bits_per_pixel is less than or equal to 32.
# * For XY formats, bitmap_unit is always less than or equal to bitmap_pad.
# * For XY formats, bitmap_unit is 8, 16, or 32 bits.
# * For Z format, bits_per_pixel is 1, 4, 8, 16, 24, or 32 bits.
# */
# static _xynormalizeimagebits (bp, img)
# register unsigned char *bp;
# register XImage *img;
# {
# register unsigned char c;
#
# if (img->byte_order != img->bitmap_bit_order) {
# switch (img->bitmap_unit) {
#
# case 16:
# c = *bp;
# *bp = *(bp + 1);
# *(bp + 1) = c;
# break;
#
# case 32:
# c = *(bp + 3);
# *(bp + 3) = *bp;
# *bp = c;
# c = *(bp + 2);
# *(bp + 2) = *(bp + 1);
# *(bp + 1) = c;
# break;
# }
# }
# if (img->bitmap_bit_order == MSBFirst)
# _XReverse_Bytes (bp, img->bitmap_unit >> 3);
# }
#
# static _znormalizeimagebits (bp, img)
# register unsigned char *bp;
# register XImage *img;
# {
# register unsigned char c;
# switch (img->bits_per_pixel) {
#
# case 4:
# *bp = ((*bp >> 4) & 0xF)
| ((*bp << 4) & ~0xF);
# break;
#
# case 16:
# c = *bp;
# *bp = *(bp + 1);
# *(bp + 1) = c;
# break;
#
# case 24:
# c = *(bp + 2);
# *(bp + 2) = *bp;
# *bp = c;
# break;
#
# case 32:
# c = *(bp + 3);
# *(bp + 3) = *bp;
# *bp = c;
# c = *(bp + 2);
# *(bp + 2) = *(bp + 1);
# *(bp + 1) = c;
# break;
# }
# }
# /*
# * GetPixel
# *
# * Returns the specified pixel. The X and Y coordinates are relative to
# * the origin (upper left [0,0]) of the image. The pixel value is returned
# * in normalized format, i.e. the LSB of the long is the LSB of the pixel.
# * The algorithm used is:
# *
# * copy the source bitmap_unit or Zpixel into temp
# * normalize temp if needed
# * extract the pixel bits into return value
# *
# */
#
# static unsigned long Const low_bits_table[] = {
# 0x00000000, 0x00000001, 0x00000003, 0x00000007,
# 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
# 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
# 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
# 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
# 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
# 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
# 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
# 0xffffffff
# };
#
# static unsigned long _XGetPixel (ximage, x, y)
# register XImage *ximage;
# int x;
# int y;
#
# {
# unsigned long pixel, px;
# register char *src;
# register char *dst;
# register int i, j;
# int bits, nbytes;
# long plane;
#
# if (ximage->depth == 1) {
# src = &ximage->data[XYINDEX(x, y, ximage)];
# dst = (char *)&pixel;
# pixel = 0;
# for (i = ximage->bitmap_unit >> 3; --i >= 0; ) *dst++ = *src++;
# XYNORMALIZE(&pixel, ximage);
# bits = (x + ximage->xoffset) % ximage->bitmap_unit;
# pixel = ((((char *)&pixel)[bits>>3])>>(bits&7)) & 1;
# } else if (ximage->format == XYPixmap) {
# pixel = 0;
# plane = 0;
# nbytes = ximage->bitmap_unit >> 3;
# for (i = ximage->depth; --i >= 0; ) {
# src = &ximage->data[XYINDEX(x, y, ximage)+ plane];
# dst = (char *)&px;
# px = 0;
# for (j = nbytes; --j >= 0; ) *dst++ = *src++;
# XYNORMALIZE(&px, ximage);
# bits = (x + ximage->xoffset) % ximage->bitmap_unit;
# pixel = (pixel << 1)
|
# (((((char *)&px)[bits>>3])>>(bits&7)) & 1);
# plane = plane + (ximage->bytes_per_line * ximage->height);
# }
# } else if (ximage->format == ZPixmap) {
# src = &ximage->data[ZINDEX(x, y, ximage)];
# dst = (char *)&px;
# px = 0;
# for (i = (ximage->bits_per_pixel + 7) >> 3; --i >= 0; )
# *dst++ = *src++;
# ZNORMALIZE(&px, ximage);
# pixel = 0;
# for (i=sizeof(unsigned long); --i >= 0; )
# pixel = (pixel << 8)
| ((unsigned char *)&px)[i];
# if (ximage->bits_per_pixel == 4) {
# if (x & 1)
# pixel >>= 4;
# else
# pixel &= 0xf;
# }
# } else {
# return 0; /* bad image */
# }
# if (ximage->bits_per_pixel == ximage->depth)
# return pixel;
# else
# return (pixel & low_bits_table[ximage->depth]);
# }
#
# /*
# * PutPixel
# *
# * Overwrites the specified pixel. The X and Y coordinates are relative to
# * the origin (upper left [0,0]) of the image. The input pixel value must be
# * in normalized format, i.e. the LSB of the long is the LSB of the pixel.
# * The algorithm used is:
# *
# * copy the destination bitmap_unit or Zpixel to temp
# * normalize temp if needed
# * copy the pixel bits into the temp
# * renormalize temp if needed
# * copy the temp back into the destination image data
# *
# */
#
#
# static int _XPutPixel (ximage, x, y, pixel)
# register XImage *ximage;
# int x;
# int y;
# unsigned long pixel;
#
# {
# unsigned long px, npixel;
# register char *src;
# register char *dst;
# register int i;
# int j, nbytes;
# long plane;
#
# if (ximage->depth == 4)
# pixel &= 0xf;
# npixel = pixel;
# for (i=0, px=pixel; i<sizeof(unsigned long); i++, px>>=8)
# ((unsigned char *)&pixel)[i] = px;
# if (ximage->depth == 1) {
# src = &ximage->data[XYINDEX(x, y, ximage)];
# dst = (char *)&px;
# px = 0;
# nbytes = ximage->bitmap_unit >> 3;
# for (i = nbytes; --i >= 0; ) *dst++ = *src++;
# XYNORMALIZE(&px, ximage);
# i = ((x + ximage->xoffset) % ximage->bitmap_unit);
# _putbits ((char *)&pixel, i, 1, (char *)&px);
# XYNORMALIZE(&px, ximage);
# src = (char *) &px;
# dst = &ximage->data[XYINDEX(x, y, ximage)];
# for (i = nbytes; --i >= 0; ) *dst++ = *src++;
# } else if (ximage->format == XYPixmap) {
# plane = (ximage->bytes_per_line * ximage->height) *
# (ximage->depth - 1); /* do least signif plane 1st */
# nbytes = ximage->bitmap_unit >> 3;
# for (j = ximage->depth; --j >= 0; ) {
# src = &ximage->data[XYINDEX(x, y, ximage) + plane];
# dst = (char *) &px;
# px = 0;
# for (i = nbytes; --i >= 0; ) *dst++ = *src++;
# XYNORMALIZE(&px, ximage);
# i = ((x + ximage->xoffset) % ximage->bitmap_unit);
# _putbits ((char *)&pixel, i, 1, (char *)&px);
# XYNORMALIZE(&px, ximage);
# src = (char *)&px;
# dst = &ximage->data[XYINDEX(x, y, ximage) + plane];
# for (i = nbytes; --i >= 0; ) *dst++ = *src++;
# npixel = npixel >> 1;
# for (i=0, px=npixel; i<sizeof(unsigned long); i++, px>>=8)
# ((unsigned char *)&pixel)[i] = px;
# plane = plane - (ximage->bytes_per_line * ximage->height);
# }
# } else if (ximage->format == ZPixmap) {
# src = &ximage->data[ZINDEX(x, y, ximage)];
# dst = (char *)&px;
# px = 0;
# nbytes = (ximage->bits_per_pixel + 7) >> 3;
# for (i = nbytes; --i >= 0; ) *dst++ = *src++;
# ZNORMALIZE(&px, ximage);
# _putbits ((char *)&pixel,
# (x * ximage->bits_per_pixel) & 7,
# ximage->bits_per_pixel, (char *)&px);
# ZNORMALIZE(&px, ximage);
# src = (char *)&px;
# dst = &ximage->data[ZINDEX(x, y, ximage)];
# for (i = nbytes; --i >= 0; ) *dst++ = *src++;
# } else {
# return 0; /* bad image */
# }
# return 1;
# }