Drawing custom widgets

customcanvas.C gives a simplified example of drawing custom widgets 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 widget. 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 widget'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 widget 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 widget'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 widgets 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 widgets scratch buffer.

The x::w::scratch_and_mask_buffer_draw mixin template's constructor has an additional parameter that specifies 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 widgets that specify the same scratch buffer label share the same underlying scratch buffer. Widgets 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 widget 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, widget 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 widget. 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 widgets whose sizes are similar. Widgets of vastly different sizes need to use different scratch buffer labels.

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

    Widgets 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 widget'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 widget).

    But this means that having both a very wide and a very tall widget 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 widget.

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