Drawing custom display elements

customcanvas.C gives a simplified example of drawing custom display elements by inheriting from x::w::scratch_and_mask_buffer_draw and implementing its do_draw():

void my_canvas_implObj::do_draw(ONLY IN_THREAD,
                const x::w::draw_info &di,
                const x::w::picture &area_picture,
                const x::w::pixmap &area_pixmap,
                const x::w::gc &area_gc,

                const x::w::picture &mask_picture,
                const x::w::pixmap &mask_pixmap,
                const x::w::gc &mask_gc,

                const x::w::clip_region_set &clipped,
                const x::w::rectangle &area_entire_rect)
{

do_draw() first two parameters are an internal execution thread signature and an x::w::draw_info object that's needed by some drawing-related methods in the parent class, should they be used. The next set of parameters provide a x::w::pixmap, x::w::gc, and x::w::picture objects representing the scratch buffer for drawing the display element. These LibCXXW objects implement most operations on pixmap, graphic contexts, and picture objects, as specified by the underlying X protocol and the RENDER extension. For more information see the protocol documentation and these objects' documentation.

The area_entire_rect parameter describes the rectangle that do_draw() should draw. This simplified drawing interface always has the display element's current size reflected in the rectangle's width and height, and the x and y coordinates are always zero. In other words: the entire rectangle.

do_draw() does not draw the display element directly in its window. The area_picture, area_pixmap, and area_gc parameters refer to a scratch buffer. This scratch buffer gets cleared to the display element's background color before do_draw() gets called. The scratch buffer's contents get copied to the window when do_draw() returns. This approach results in flicker-free drawing.

A second set of picture, pixmap, and graphic context objects refer to a second scratch buffer. This is a 1-bit deep scratch buffer for preparing any masking operations for compositing the main area scratch buffer's image. The contents of the scratch buffer do not get cleared. do_draw() is responsible for clearing its masking scratch buffer before using it.

Scratch buffers

Custom display elements must provide an identifying label for their scratch buffers. This label is a plain text string. Their x::w::child_elementObj parent class's constructor takes a child_element_init_params parameter with a scratch_buffer_id. This specifies the label for the display elements scratch buffer.

The x::w::scratch_and_mask_buffer_draw mixin template's constructor has an additional parameter specifying the masking scratch buffer's label.

These labels are plain text strings that uniquely identify a scratch buffer. LibCXXW treats them as opaque identifiers, and display elements that specify the same scratch buffer label share the same underlying scratch buffer. Display elements that specify different labels get separate scratch buffers.

Note

A scratch buffer's unique identifier is actually its label and its x::w::pictformat, The same label with a regular scratch buffer and a one bit-deep masking buffer creates two actual, independent, scratch buffers.

The scratch buffers get sized appropriately for each display element that uses them. For that reason do_draw() can get a scratch buffer that's actually bigger than the drawing rectangle's size because another, larger, display element shares the same scratch buffer.

Use the following convention for specifying scratch buffer labels:

  • Each label should be formatted as either an E-mail address or an Internet hostname, using the domain that belongs to the application that uses the custom display element. An application developed by example.com can use circle@labels.example.com, or circle.labels.example.com. LibCXXW's internal dialog identifiers use this convention, and this avoids conflicts for that reason.

  • Use the same scratch buffer label with display elements whose sizes are similar. Display elements of vastly different sizes need to use different scratch buffer labels.

    If a very wide display element uses the same label as another display element that's very tall, the resulting scratch buffer becomes both as wide as as tall as both of these display elements combined together. These two display elements end up using the same underlying scratch buffer, which becomes wasteful.

    Display elements don't need to have identical sizes in order to share a scratch buffer. Close enough is good enough. The library simply sizes the scratch buffer, on demand, to accomodate each display element's requested size, so the scratch buffer ends up being big enough to keep everyone happy (LibCXXW actually tries to stay ahead of the game by proactively sizing the scratch buffer with extra room to spare, for growth, in hopes of avoiding a reallocation forced by a larger display element).

    But this means that having both a very wide and a very tall display element ends up with a scratch buffer wasting a lot of valuable display memory (pixmap memory gets allocated on the display server, after all) in order to accomodate both a very wide and a very tall display element.

    By naming scratch buffer labels using Internet domain names, this avoids accidental reuse of the same label by different libraries/applications for display elements with widely different sizes.