expose()expose()Nameexpose - 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 struc‐
ture, 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 bound‐
ing box of the exposed area. region is NULL if there is no exposure
compression, or specifies the union of all exposure events in the com‐
pressed 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 "Back‐
ground" 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 han‐
dling expose events on a widget.
Usage
The expose() method is responsible for initially drawing into a wid‐
get'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 possi‐
ble 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 rectan‐
gles may slow down your widget. The cost/benefit ratio should be exam‐
ined.
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 indi‐
cate 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 sub‐
classes 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 spe‐
cial 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 com‐
plex 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 wid‐
get's expose procedure. This field must be set to XtExposeNoCompress,
XtExposeCompressSeries, XtExposeCompressMultiple, or XtExposeCompress‐
Maximal, optionally ORed with any combination of the XtExposeGraphic‐
sExpose, 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 wid‐
get'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 coa‐
lesced into a single event without regard to intervening non-expo‐
sure 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 XtExposeCom‐
pressMaximal 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 XtExposeGraphicsExpose.
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. How‐
ever, 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 guaranteed 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 AlsoCore(3).
Xt - Intrinsics Methods expose()