expose() expose()
Name
expose - Core class method that draws a widget's graphics.
Synopsis
typedef void (*XtExposeProc)(Widget, XEvent *, Region);
Widget w;
XEvent *event;
Region region;
Inputs
w Specifies the widget instance requiring redisplay.
event Specifies the exposure event giving the rectangle requiring redisplay.
region Specifies the union of all rectangles in this exposure sequence.
Description
The expose() method is installed on the expose field of the Core class part structure, and is called to draw or redraw the widget's window
when exposure events arrive for that window. An expose() method may also be registered on the expose field of the RectObj class part
structure, but because RectObj widgets do not have windows, this method will not be called by the Intrinsics. (Although some composite
widgets may call the expose() methods of their non-widget children.)
The w argument is the widget for which exposure events have arrived. event is the exposure event, or the latest in a series of exposure
events, if the widget uses exposure compression. It contains a bounding box of the exposed area. region is NULL if there is no exposure
compression, or specifies the union of all exposure events in the compressed sequence. The expose() method must redraw at least the graph-
ics within the bounding box of the event. Simple widgets may simply redraw their entire window; more complicated widgets may attempt to
minimize the amount of redraw required by using the region argument. Exposure compression is specified with the compress_exposure field in
the Core class part structure. See the "Background" section below for details.
A widget need not redisplay itself if it is not visible. A widget can obtain a hint about whether it is currently visible by checking the
visible field in the Core instance structure. If visible_interest in the Core class structure is True, then the visible field is usually
False if no part of the widget is currently visible. See the "Background" section for details.
The expose() method is not chained. A widget class can inherit the expose() method of its superclass by specifying XtInheritExpose on the
expose field of its RectObj or Core class part structure. A widget that does not display any graphics (such as many composite widgets) can
set this field to NULL.
The long "Usage" section below explains some common strategies to handling expose events on a widget.
Usage
The expose() method is responsible for initially drawing into a widget's window and for redrawing the window every time a part of the win-
dow becomes exposed. This redrawing is necessary because the X server does not normally maintain the contents of windows when they are
obscured. When a window becomes visible again, it must be redrawn.
Most widgets keep track of what they draw in some form of arrays or display lists. This could be an array of lines of text to be drawn,
for example, or an array of lines which can be drawn with a single call to XDrawLines(). When a widget of this sort needs to redisplay
itself, it simply calls the procedure that draws the widget based on the saved data.
The graphic contents of a widget often change in response to user events handled with action procedures or event handlers. These proce-
dures usually draw into the widget directly, but must also store the appropriate data so that the current state of the widget can be regen-
erated, if necessary.
An expose() method can be made more efficient if as much data as possible is pre-computed. A label widget that draws its text centered in
its window, for example, should pre-compute the x and y coordinates at which the text will be drawn. If it does not, the expose method
will have to compute the position based on the height of the font, the width of the string (which is time consuming to compute), and the
size of the window. These pre-computed positions should only need to be updated in the resize() and set_values() methods.
Simple widgets may just redisplay their entire window when the expose event is called. More complicated widgets may redisplay everything
within the bounding box of the event (which will be the same as the bounding box of the specified Region if it is non-NULL). For widgets
that are very time-consuming for the client or server to redraw, you might want to use this region in a more sophisticated way. You can
use this region as a clip mask in your GC (see XSetRegion()) to clip output to the exposed region, and possibly calculate which drawing
primitives affect this area. Xlib also provides region mathematics routines (such as XRectInRegion()) so that you can compare the regions
in which your widget needs to draw graphics with the region that was exposed. If certain areas do not require redrawing, you can skip the
code that redraws them. If you plan to write a sophisticated expose() method, bear in mind that the calculations required to optimize the
redisplay are time consuming, too, and too much clipping and testing of rectangles may slow down your widget. The cost/benefit ratio
should be examined.
Some widgets do not bother to remember how to redraw themselves. Instead they draw their graphics into a pixmap and copy the contents of
the pixmap into their window as needed. For some widgets this approach is much simpler than retaining the state needed to redraw from
scratch. If the widget is very large, however, the pixmap will take up a lot of memory in the X server.
A widget that is insensitive (see XtSetSensitive(1)) may wish to indicate this to the user by drawing itself in a different way. A common
approach is to draw with a GC with a stipple to so that everything appears "grayed-out."
A composite widget that accepts non-widget children which are subclasses of RectObj ("gadgets") will have to display the graphics of those
children in its own window. It may narrowly define the types of children it will accept to be the type of children that it knows how to
draw. Or instead it may require that its RectObj children have their own expose() methods and call those methods when it detects that the
region of the window occupied by a child needs to be redrawn.
If a widget has no display semantics, it can specify NULL for the expose() field. Many composite widgets serve only as containers for
their children and have no expose() method. If the expose() method is NULL, XtRealizeWidget() fills in a default bit gravity of NorthWest-
Gravity before it calls the widget's realize() method.
Example
The following procedure is the expose() method of the Xaw Label widget with code for handling the left bitmap and multi-line string
removed. Note that it first tests that the exposed region intersects the region that the label string or pixmap occupies. It also has
commented-out code that sets the region as the clipmask of the GC. For such a simple redisplay, doing the clipping may have taken more
time than simply drawing the text of pixmap. This method does not test the visible field, and the widget class has its visible_interest
field set to False. Finally, note that if the widget is insensitive, it uses a special GC to draw itself "grayed-out."
/* ARGSUSED */
static void Redisplay(w, event, region)
Widget w;
XEvent *event;
Region region;
{
LabelWidget lw = (LabelWidget) w;
GC gc;
if (region != NULL) {
int x = lw->label.label_x;
unsigned int width = lw->label.label_width;
if (lw->label.lbm_width) {
if (lw->label.label_x > (x = lw->label.internal_width))
width += lw->label.label_x - x;
}
if (XRectInRegion(region, x, lw->label.label_y,
width, lw->label.label_height) == RectangleOut)
return;
}
gc = XtIsSensitive((Widget)lw) ? lw->label.normal_GC : lw->label.gray_GC;
#ifdef notdef
if (region != NULL) XSetRegion(XtDisplay(w), gc, region);
#endif /*notdef*/
if (lw->label.pixmap == None) {
int len = lw->label.label_len;
char *label = lw->label.label;
Position y = lw->label.label_y + lw->label.font->max_bounds.ascent;
if (len) {
if (lw->label.encoding)
XDrawString16(XtDisplay(w), XtWindow(w), gc,
lw->label.label_x, y, (TXT16*)label, len/2);
else
XDrawString(XtDisplay(w), XtWindow(w), gc,
lw->label.label_x, y, label, len);
}
} else if (lw->label.label_len == 1) { /* depth */
XCopyPlane(XtDisplay(w), lw->label.pixmap, XtWindow(w), gc,
0, 0, lw->label.label_width, lw->label.label_height,
lw->label.label_x, lw->label.label_y, 1L);
} else {
XCopyArea(XtDisplay(w), lw->label.pixmap, XtWindow(w), gc,
0, 0, lw->label.label_width, lw->label.label_height,
lw->label.label_x, lw->label.label_y);
}
#ifdef notdef
if (region != NULL) XSetClipMask(XtDisplay(w), gc, (Pixmap)None);
#endif /* notdef */
}
Background
Many widgets prefer to process a series of exposure events as a single expose region rather than as individual rectangles. Widgets with
complex displays might use the expose region as a clip list in a graphics context, and widgets with simple displays might ignore the region
entirely and redisplay their whole window or might get the bounding box from the region and redisplay only that rectangle.
In either case, these widgets want some kind of exposure compression. The compress_exposure field in the widget class structure specifies
the type and number of exposure events that will be dispatched to the widget's expose procedure. This field must be set to XtExposeNoCom-
press, XtExposeCompressSeries, XtExposeCompressMultiple, or XtExposeCompressMaximal, optionally ORed with any combination of the XtExposeG-
raphicsExpose, XtExposeGraphicsExposeMerged, and XtExposeNoExpose flags. (Specifying False for the compress_exposure field is equivalent
to XtExposeNoCompress with no flags and specifying True is equivalent to XtExposeCompressSeries with no flags.)
If the compress_exposure field in the widget class structure does not specify XtExposeNoCompress, the event manager calls the widget's
expose procedure only once for a series of exposure events. In this case, all Expose or GraphicsExpose events are accumulated into a
region. When the final event is received, the event manager replaces the rectangle in the event with the bounding box for the region and
calls the widget's expose() method, passing the modified exposure event and the region.
The different types of exposure compression are as follows:
XtExposeNoCompress
No exposure compression is performed; every selected event is individually dispatched to the expose procedure with a region argument
of NULL.
XtExposeCompressSeries
Each series of exposure events is coalesced into a single event, which is dispatched when an exposure event with count equal to zero
is reached.
XtExposeCompressMultiple
Consecutive series of exposure events are coalesced into a single event, which is dispatched when an exposure event with count equal
to zero is reached and either the event queue is empty or the next event is not an exposure event for the same widget.
XtExposeCompressMaximal
All expose series currently in the queue for the widget are coalesced into a single event without regard to intervening non-exposure
events. If a partial series is in the end of the queue, the Intrinsics will block until the end of the series is received.
The optional flags have the following meanings:
XtExposeGraphicsExpose
Specifies that GraphicsExpose events are also to be dispatched to the expose procedure. GraphicsExpose events will be compressed, if
specified, in the same manner as Expose events.
XtExposeGraphicsExposeMerged
Specifies in the case of XtExposeCompressMultiple and XtExposeCompressMaximal that a series of GraphicsExpose and Expose events are to
be compressed together, with the final event type determining the type of the event passed to the expose procedure. If this flag is
not set, then only series of the same event type as the event at the head of the queue are coalesced. This flag also implies XtEx-
poseGraphicsExpose.
XtExposeNoExpose
Specifies that NoExpose events are also to be dispatched to the expose procedure. NoExpose events are never coalesced with other
exposure events or with each other.
Some widgets use substantial computing resources to display data. However, this effort is wasted if the widget is not actually visible on
the screen (e.g., when the widget is obscured by another application or is iconified). The visible field in the Core widget instance
structure provides the widget with a hint that it need not display data. If any part of the widget is visible, the visible field is guar-
anteed to be True by the time an Expose event is processed; if the widget is not visible, this field is usually False.
Widgets can either use or ignore the visible hint. If they ignore it, the visible_interest field in their widget class record should be
set to False. In this case, the visible field is initialized to True and never changes. If visible_interest is True, however, the event
manager asks for VisibilityNotify events for the widget and updates the visible field accordingly.
Structures
Region is an opaque type defined by Xlib.
See Also
Core(3).
Xt - Intrinsics Methods expose()