XEvent *xevent = event_xevent(event);
if (xevent->xany.type == Expose && xevent->xexpose.count == 0) {
Display *dpy = (Display *)xv_get(logo_public, XV_DISPLAY);
Window window = (Window)xv_get(logo_public, XV_XID);
int width = (int)xv_get(logo_public, XV_WIDTH);
int height = (int)xv_get(logo_public, XV_HEIGHT);
int x = (width - xlogo32_width)/2;
int y = (height - xlogo32_height)/2;
XCopyPlane(dpy, logo_private->bitmap, window, logo_private->gc,
0, 0, xlogo32_width, xlogo32_height, x, y, 1L);
} else if (xevent->xany.type == ConfigureNotify)
XClearArea(xv_get(logo_public, XV_DISPLAY),
xv_get(logo_public, XV_XID), 0, 0,
xevent->xconfigure.width, xevent->xconfigure.height, True);
}
The ConfigureNotify event is tested to see if the window resized. If it did, the window
needs to be cleared and the logo redrawn in the new center of the window. The window is
cleared using XClearArea() and passing True as the last parameter indicating that an
Expose event should be generated. When the event is delivered, logo_redraw() is
called again, and the logo is redrawn.
25.5.5 The Set Method
After the initialize routines for all the classes have been called, the set method is invoked in
reverse order (from the bottom up). That is, the generic package’s set routine is called last
and the logo’s set routine is called first.
The form of the set routine is:
Xv_opaque
set_func(pkg_public, avlist)
Xv_opaque *pkg_public;
Attr_avlist avlist;
The first parameter is a handle to the public data type representing the package. The
avlist parameter is a list of the attributes and values that have not been consumed by the
initialize routine or previously called set routines from other packages. In this routine,
package-specific attributes are scanned and evaluated, modifying the private data type ac-
cording to the attributes’ values.
Most applications ignore the return value of xv_set(), so it is usually sufficient to return
XV_OK. However, you can return anything you like. For example, your own package may
wish to return the previous value of an attribute if xv_set() was used to change it. This
may not be clearly defined, as xv_set() can be called to set many attributes.
Here is the set routine for the logo package:
logo_set(logo_public, avlist)
Logo_public *logo_public;
Attr_avlist avlist;
{
XView Internals
XView Internals 599
Logo_private *logo_private = LOGO_PRIVATE(logo_public);
Attr_attribute *attrs;
for (attrs = avlist; *attrs; attrs = attr_next(attrs))
switch ((int) attrs[0 ]) {
case XV_END_CREATE : {
/* this stuff *must* be here rather than in the "init"
* routine because the CMS is not loaded into the
* window object until the "set" routines are called.
*/
Cms cms = xv_get(logo_public, WIN_CMS);
XGCValues gcvalues;
Display *dpy =
(Display *)xv_get(logo_public, XV_DISPLAY);
gcvalues.foreground =
x(unsigned long)v_get(cms, CMS_FOREGROUND_PIXEL);
gcvalues.background =
(unsigned long)xv_get(cms, CMS_BACKGROUND_PIXEL);
gcvalues.graphics_exposures = False;
logo_private->gc = XCreateGC(dpy,
xv_get(logo_public, XV_XID),
GCForeground|GCBackground|GCGraphicsExposures,
&gcvalues);
}
default :
xv_check_bad_attr(LOGO, attrs[0]);
break;
}
return XV_OK;
}
A handle to the logo’s private data structure is needed since the set routine changes the value
of fields within that structure. The LOGO_PRIVATE() macro is used to get a pointer to the
private data from the public object.
Since the logo package has no attributes, there is no need to scan for attributes specific to the
logo package or any other package. Recall, however, that we still need to initialize the GC
for the logo. Therefore, we scan for the XV_END_CREATE attribute.
NOTE
The set routine must return XV_OK when XV_END_CREATE is in the avlist.
Any other return value causes XView to assume that there was an error in initial-
ization.
At this point in time, the WINDOW package has initialized itself completely and we can there-
fore get the colors from the window’s colormap segment. We use xv_get() and ask for its
WIN_CMS.
The example Bitmap package goes into more detail about the set routine.
600 XView Programming Manual
25.5.6 The Get Method
The get method is simple: it basically returns the value of the attribute specified in the pro-
grammer’s call to xv_get(). The form of the get function is:
Xv_opaque
get_func(pkg_public, status, attr, avlist)
pkg_public *pkg_public;
int *status;
Attr_attribute attr;
Attr_avlist avlist;
The attr parameter is the attribute for which the programmer wants the value.* However,
there are some attributes used by xv_get() that take an additional parameter. For example,
when using CANVAS_NTH_VIEW, an additional int parameter is required to indicate which
view to return. For such cases, the additional parameter(s) is in the avlist.
The status parameter must be set by the get routine to XV_ERROR if there is an error.
The calling sequence for the get method is from the bottom up—that is, the specific packages
are called first followed by each parent up the chain to the generic object. Each class in the
chain is called until one of them sets the status parameter to XV_OK.
If an unknown attribute is requested, status should be set to XV_ERROR, but the function
should return XV_OK. This tells XView that the attribute requested does not belong to this
package and that it should try the next package in the chain.
Here is the get function for the logo object:
logo_get(logo_public, status, attr, args)
Logo_public *logo_public;
int *status;
Attr_attribute attr;
Attr_avlist args;
{
*status = xv_check_bad_attr(LOGO, attr);
return (Xv_opaque)XV_OK;
}
Since the logo object has no attributes, it sets the status parameter and returns. As noted
earlier, since there are no attributes specific to the logo package, this routine is unnecessary;
we could have declared the function pointer as NULL in the Xv_pkg data structure causing
the get method for this package to be unused.
A more detailed discussion of the get method, including a discussion on
xv_check_bad_attr(), is given in the example Bitmap package.
*Remember, xv_get() can only be used to get the value of one attribute.
XView Internals
XView Internals 601
25.5.7 The Destroy Method
When the programmer calls xv_destroy() or if XView decides to destroy objects or
classes externally, the destroy method for the package is called. The calling sequence for the
destroy method is from the bottom up, as it is for the get method.
The main task of the destroy routine is to free the private data type and any other cleanup that
may accompany it. This includes freeing allocated data, closing open file descriptors, unlink-
ing temp files, and so on. However, this is not the only reason the destroy method is called;
in fact, there are four different reasons or conditions in which the function may be invoked.
The form of the destroy function is:
int
destroy_func(pkg_public, status)
Xv_opaque *pkg_public;
Destroy_status status;
As with all the methods, the first parameter is a handle to the public data type for the pack-
age. The status parameter is of type Destroy_status. It describes the condition for
which the function has been called. This is the same situation as the destroy_func() de-
scribed in Section 20.9.5, “Modifying a Frame’s Destruction.”
For the logo object, we need to destroy the allocated pixmap and free the allocated GC. The
logo’s destroy function is:
logo_destroy(logo_public, status)
Logo_public *logo_public;
Destroy_status status;
{
Logo_private *logo_private = LOGO_PRIVATE(logo_public);
if (status == DESTROY_CLEANUP) {
XFreePixmap(xv_get(logo_public, XV_DISPLAY),
logo_private->bitmap);
XFreeGC(xv_get(logo_public, XV_DISPLAY), logo_private->gc);
free(logo_private);
}
return XV_OK;
}
Unless the status is DESTROY_CLEANUP, nothing is freed. This assures that the instance of the
logo object remains intact in case the destroy method was invoked for other reasons. Please
consult Chapter 20, The Notifier, and Chapter 4, Frames, for details on how to handle the oth-
er conditions possible for the destroy function.
602 XView Programming Manual
25.6 Example Program Listing
At this point, we have discussed everything necessary to implement the logo object except
for a main application that creates an instance of a logo object.
Writing this application is really no different from the way it is done for any other XView
package, as you can see from Example 25-1.
Example 25-1. The logo.c program
/* logo.c -- demonstrate the use of the logo package. */
#include <xview/xview.h>
#include <xview/cms.h>
#include "logo.h"
main(argc, argv)
char *argv[ ];
{
Frame frame;
Cms cms;
Logo logo;
xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);
frame = (Frame)xv_create(NULL, FRAME, NULL);
cms = xv_create(NULL, CMS,
CMS_SIZE, 2,
CMS_NAMED_COLORS, "blue", "red", NULL,
NULL);
logo = xv_create(frame, LOGO,
XV_WIDTH, 100,
XV_HEIGHT, 100,
WIN_CMS, cms,
NULL);
window_fit(frame);
xv_main_loop(frame);
}
All the pieces are in play—the logo variable is of type Logo, the call to xv_create()
has LOGO as the package name, and the owner of the logo is the frame object. The program
allocates a colormap segment that has the colors red and blue to demonstrate that colors can
be assigned to the logo through the WINDOW package attributes. However, if this application
is run on a monochrome screen, the output is rendered in black and white, as in Figure 25-3.
The frame may be resized by the user and the logo is always redrawn in the middle of its win-
dow. This is the task of the logo_redraw() routine registered by the logo object in its
initialize routine.
The entire logo implementation module is listed in Appendix F, Example Programs.
XView Internals
XView Internals 603

Get Volume 7A: XView Programming Manual now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.