diff --git a/3rdparty/X11/xcb/xproto.d b/3rdparty/X11/xcb/xproto.d index 92ba94a3..43607e6d 100644 --- a/3rdparty/X11/xcb/xproto.d +++ b/3rdparty/X11/xcb/xproto.d @@ -475,6 +475,7 @@ struct xcb_setup_authenticate_iterator_t { int index; /**< */ } ; +alias xcb_image_order_t = int; enum :int{ XCB_IMAGE_ORDER_LSB_FIRST = 0, XCB_IMAGE_ORDER_MSB_FIRST = 1 @@ -3046,6 +3047,7 @@ struct xcb_poly_fill_arc_request_t { xcb_gcontext_t gc; /**< */ } ; +alias xcb_image_format_t = int; enum :int{ XCB_IMAGE_FORMAT_XY_BITMAP = 0, XCB_IMAGE_FORMAT_XY_PIXMAP = 1, diff --git a/examples/example1/main.d b/examples/example1/main.d index e652f458..2688016a 100644 --- a/examples/example1/main.d +++ b/examples/example1/main.d @@ -6,6 +6,8 @@ import std.stdio; version (linux) { pragma(lib, "png"); pragma(lib, "xcb"); + pragma(lib, "xcb-shm"); + pragma(lib, "xcb-image"); pragma(lib, "X11"); } diff --git a/src/dlangui/platforms/x11/x11app.d b/src/dlangui/platforms/x11/x11app.d index 7df94277..1c9f785f 100644 --- a/src/dlangui/platforms/x11/x11app.d +++ b/src/dlangui/platforms/x11/x11app.d @@ -4,16 +4,382 @@ version(linux) { import std.string; import std.c.linux.X11.xcb.xcb; +import std.c.linux.X11.xcb.shm; import std.c.linux.X11.xcb.xproto; import std.c.linux.X11.keysymdef; +import std.c.linux.linux; import std.c.stdlib; +import std.conv; import dlangui.core.logger; +import dlangui.graphics.drawbuf; import dlangui.platforms.common.platform; +struct xcb_image_t +{ + ushort width; + ushort height; + xcb_image_format_t format; + ubyte scanline_pad; + ubyte depth; + ubyte bpp; + ubyte unit; + uint plane_mask; + xcb_image_order_t byte_order; + xcb_image_order_t bit_order; + uint stride; + uint size; + void * base; + ubyte * data; +} + +xcb_format_t * +find_format_by_depth (xcb_setup_t *setup, ubyte depth) +{ + xcb_format_t *fmt = xcb_setup_pixmap_formats(setup); + xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length(setup); + for(; fmt != fmtend; ++fmt) + if(fmt.depth == depth) + return fmt; + return null; +} + + +xcb_image_format_t +effective_format(xcb_image_format_t format, ubyte bpp) +{ + if (format == XCB_IMAGE_FORMAT_Z_PIXMAP && bpp != 1) + return format; + return XCB_IMAGE_FORMAT_XY_PIXMAP; +} + + +int +format_valid (ubyte depth, ubyte bpp, ubyte unit, + xcb_image_format_t format, ubyte xpad) +{ + xcb_image_format_t ef = effective_format(format, bpp); + if (depth > bpp) + return 0; + switch(ef) { + case XCB_IMAGE_FORMAT_XY_PIXMAP: + switch(unit) { + case 8: + case 16: + case 32: + break; + default: + return 0; + } + if (xpad < bpp) + return 0; + switch (xpad) { + case 8: + case 16: + case 32: + break; + default: + return 0; + } + break; + case XCB_IMAGE_FORMAT_Z_PIXMAP: + switch (bpp) { + case 4: + if (unit != 8) + return 0; + break; + case 8: + case 16: + case 24: + case 32: + if (unit != bpp) + return 0; + break; + default: + return 0; + } + break; + default: + return 0; + } + return 1; +} + + +int +image_format_valid (xcb_image_t *image) { + return format_valid(image.depth, + image.bpp, + image.unit, + image.format, + image.scanline_pad); +} + +uint xcb_roundup(uint base, + uint pad +) +{ + uint b = base + pad - 1; + /* faster if pad is a power of two */ + if (((pad - 1) & pad) == 0) + return b & -pad; + return b - b % pad; +} + +void +xcb_image_annotate (xcb_image_t *image) +{ + xcb_image_format_t ef = effective_format(image.format, image.bpp); + switch (ef) { + case XCB_IMAGE_FORMAT_XY_PIXMAP: + image.stride = xcb_roundup(image.width, image.scanline_pad) >> 3; + image.size = image.height * image.stride * image.depth; + break; + case XCB_IMAGE_FORMAT_Z_PIXMAP: + image.stride = xcb_roundup(cast(uint)image.width * + cast(uint)image.bpp, + image.scanline_pad) >> 3; + image.size = image.height * image.stride; + break; + default: + assert(0); + } +} + +xcb_image_t * +xcb_image_create_native (xcb_connection_t * c, + ushort width, + ushort height, + xcb_image_format_t format, + ubyte depth, + void * base, + uint bytes, + ubyte * data) +{ + xcb_setup_t * setup = xcb_get_setup(c); + xcb_format_t * fmt; + xcb_image_format_t ef = format; + + if (ef == XCB_IMAGE_FORMAT_Z_PIXMAP && depth == 1) + ef = XCB_IMAGE_FORMAT_XY_PIXMAP; + switch (ef) { + case XCB_IMAGE_FORMAT_XY_BITMAP: + if (depth != 1) + return null; + /* fall through */ + case XCB_IMAGE_FORMAT_XY_PIXMAP: + if (depth > 1) { + fmt = find_format_by_depth(setup, depth); + if (!fmt) + return null; + } + return xcb_image_create(width, height, format, + setup.bitmap_format_scanline_pad, + depth, depth, setup.bitmap_format_scanline_unit, + setup.image_byte_order, + setup.bitmap_format_bit_order, + base, bytes, data); + case XCB_IMAGE_FORMAT_Z_PIXMAP: + fmt = find_format_by_depth(setup, depth); + if (!fmt) + return null; + return xcb_image_create(width, height, format, + fmt.scanline_pad, + fmt.depth, fmt.bits_per_pixel, 0, + setup.image_byte_order, + XCB_IMAGE_ORDER_MSB_FIRST, + base, bytes, data); + default: + assert(0); + } + assert(0); +} + +uint xcb_mask(uint n) +{ + return n == 32 ? ~0 : (1 << n) - 1; +} + +xcb_image_t * +xcb_image_create (ushort width, + ushort height, + xcb_image_format_t format, + ubyte xpad, + ubyte depth, + ubyte bpp, + ubyte unit, + xcb_image_order_t byte_order, + xcb_image_order_t bit_order, + void * base, + uint bytes, + ubyte * data) +{ + xcb_image_t * image; + + if (unit == 0) { + switch (format) { + case XCB_IMAGE_FORMAT_XY_BITMAP: + case XCB_IMAGE_FORMAT_XY_PIXMAP: + unit = 32; + break; + case XCB_IMAGE_FORMAT_Z_PIXMAP: + if (bpp == 1) { + unit = 32; + break; + } + if (bpp < 8) { + unit = 8; + break; + } + unit = bpp; + break; + default: + break; + + } + } + if (!format_valid(depth, bpp, unit, format, xpad)) + return null; + import std.c.stdlib; + image = cast(xcb_image_t*)malloc(xcb_image_t.sizeof); + if (image is null) + return null; + image.width = width; + image.height = height; + image.format = format; + image.scanline_pad = xpad; + image.depth = depth; + image.bpp = bpp; + image.unit = unit; + image.plane_mask = xcb_mask(depth); + image.byte_order = byte_order; + image.bit_order = bit_order; + xcb_image_annotate(image); + + /* + * Ways this function can be called: + * * with data: we fail if bytes isn't + * large enough, else leave well enough alone. + * * with base and !data: if bytes is zero, we + * default; otherwise we fail if bytes isn't + * large enough, else fill in data + * * with !base and !data: we malloc storage + * for the data, save that address as the base, + * and fail if malloc does. + * + * When successful, we establish the invariant that data + * points at sufficient storage that may have been + * supplied, and base is set iff it should be + * auto-freed when the image is destroyed. + * + * Except as a special case when base = 0 && data == 0 && + * bytes == ~0 we just return the image structure and let + * the caller deal with getting the allocation right. + */ + if (!base && !data && bytes == ~0) { + image.base = null; + image.data = null; + return image; + } + if (!base && data && bytes == 0) + bytes = image.size; + image.base = base; + image.data = data; + if (!image.data) { + if (image.base) { + image.data = cast(ubyte*)image.base; + } else { + bytes = image.size; + image.base = malloc(bytes); + image.data = cast(ubyte*)image.base; + } + } + if (!image.data || bytes < image.size) { + free(image); + return null; + } + return image; +} + + +void +xcb_image_destroy (xcb_image_t *image) +{ + if (image.base) + free (image.base); + free (image); +} + +ubyte +xcb_aux_get_depth(xcb_connection_t *c, + xcb_screen_t *screen) +{ + xcb_drawable_t drawable; + xcb_get_geometry_reply_t *geom; + ubyte depth; + + drawable = screen.root; + geom = xcb_get_geometry_reply (c, xcb_get_geometry(c, drawable), null); + + if (!geom) { + Log.e("GetGeometry(root) failed"); + exit (0); + } + + depth = geom.depth; + free (geom); + + return depth; +} + +extern (C) int xcb_image_shm_get(xcb_connection_t * conn, + xcb_drawable_t draw, + xcb_image_t * image, + xcb_shm_segment_info_t shminfo, + ushort x, + ushort y, + uint plane_mask); +const XCB_ALL_PLANES = ~0; + +extern (C) xcb_image_t * +xcb_image_shm_put (xcb_connection_t * conn, + xcb_drawable_t draw, + xcb_gcontext_t gc, + xcb_image_t * image, + xcb_shm_segment_info_t shminfo, + short src_x, + short src_y, + short dest_x, + short dest_y, + ushort src_width, + ushort src_height, + ubyte send_event); + +/** + * @struct xcb_shm_segment_info_t + * A structure that stores the informations needed by the MIT Shm + * Extension. + */ +struct xcb_shm_segment_info_t +{ + xcb_shm_seg_t shmseg; + uint shmid; + ubyte *shmaddr; +} + +alias int key_t; +extern (C) int shmget(key_t key, size_t size, int shmflg); +extern (C) int getpagesize(); +extern (C) ubyte *shmat(int shmid, ubyte *shmaddr, int shmflg); +extern (C) int shmctl(int shmid, int cmd, void *buf); +const IPC_CREAT = octal!1000; +const IPC_PRIVATE = (cast(key_t) 0); +const IPC_RMID = 0; class XCBWindow : Window { xcb_window_t _w; xcb_gcontext_t _g; + xcb_image_t * _image; + xcb_shm_segment_info_t shminfo; @property xcb_window_t windowId() { return _w; } this(string caption, Window parent) { _caption = caption; @@ -55,6 +421,88 @@ class XCBWindow : Window { windowCaption = _caption; return true; } + + void createImage() { + Log.i("CRXCBScreen::createImage ", _dx, "x", _dy); + if (_image) + xcb_image_destroy(_image); + _image = null; + xcb_shm_query_version_reply_t * rep_shm; + rep_shm = xcb_shm_query_version_reply (_xcbconnection, + xcb_shm_query_version(_xcbconnection), + null); + if(rep_shm) { + xcb_image_format_t format; + int shmctl_status; + + if (rep_shm.shared_pixmaps && + (rep_shm.major_version > 1 || rep_shm.minor_version > 0)) + format = cast(xcb_image_format_t)rep_shm.pixmap_format; + else + format = XCB_IMAGE_FORMAT_Z_PIXMAP; + + _image = xcb_image_create_native (_xcbconnection, cast(short)_dx, cast(short)_dy, + format, _xcbscreendepth, null, ~0, null); + //format, depth, NULL, ~0, NULL); + //format, depth, NULL, ~0, NULL); + assert(_image); + + shminfo.shmid = shmget (IPC_PRIVATE, + _image.stride*_image.height, + IPC_CREAT | octal!777); + assert(shminfo.shmid != cast(uint)-1); + shminfo.shmaddr = cast(ubyte*)shmat (shminfo.shmid, null, 0); + assert(shminfo.shmaddr); + _image.data = shminfo.shmaddr; + Log.d("Created image depth=", _image.depth, " bpp=", _image.bpp, " stride=", _image.stride ); + + shminfo.shmseg = xcb_generate_id (_xcbconnection); + xcb_shm_attach (_xcbconnection, shminfo.shmseg, + shminfo.shmid, 0); + shmctl_status = shmctl(shminfo.shmid, IPC_RMID, null); + assert(shmctl_status != -1); + free(rep_shm); + } else { + Log.e("Can't get shms"); + } + } + + void draw(ColorDrawBuf buf) { + int i; + i = xcb_image_shm_get(_xcbconnection, _w, + _image, shminfo, + 0, 0, + XCB_ALL_PLANES); + if (!i) { + Log.e("cannot get shm image"); + return; + } + Rect rc; + rc.right = buf.width; + rc.bottom = buf.height; + switch ( _image.bpp ) { + case 32: + { + for (int y = rc.top; y