The types Xv_public and Xv_private are both defined to be extern to indicate that
they may be called from outside of the files they are declared in. However, the meaning of
these types indicates the intended use of the function. Programmers should never call “pri-
vate” functions, whereas they are allowed to call the public ones. It is assumed that the pri-
vate functions are those that aid in the implementation of the package. Again, functions
should be declared as static whenever possible.
25.5.3 The Package Declaration
A package is declared by initializing a global variable of type Xv_pkg. All the fields of the
data structure are initialized to identify the package. The logo package is declared by creat-
ing a logo_pkg variable of this type.*
Xv_pkg logo_pkg = {
"Logo", /* package name */
ATTR_PKG_UNUSED_FIRST, /* package ID */
sizeof(Logo_public), /* size of the public struct */
WINDOW, /* subclassed from the WINDOW package */
logo_init,
logo_set,
logo_get,
logo_destroy,
NULL /* disable the use of xv_find() */
};
The package ID is set to ATTR_PKG_UNUSED_FIRST because it is assumed that this is the first
unused package in the XView library. In short, a package ID only needs to be distinct from
the IDs of parent and child packages. While this is the only requirement imposed by XView,
it is still recommended that all packages have unique package IDs. The value of the package
ID must fall within the range ATTR_PKG_UNUSED_FIRST through ATTR_PKG_UNUSED_LAST.
The size_of_public field of the logo_pkg is set to the size of the public structure us-
ing the C macro sizeof(). The XView intrinsics initialize the public structure before cal-
ling the initialize method by allocating the number of bytes set by this field.
The parent package from which the logo package is subclassed is set in the parent_pkg
field. This field is initialized to the WINDOW package. You may recall that this is a macro that
refers to the address of the WINDOW package’s global variable: xv_window_pkg (implying
that the two are interchangeable).
The rest of the fields in the logo_pkg structure are initialized to the pointers to the appro-
priate functions. Notice, however, that the find method is disabled by having its field initial-
ized to
NULL. Any routine that does not apply to a particular package may be set to NULL;
XView will not try to invoke NULL methods.
*This declaration may be done in the file that contains the package implementation. However, for systems with
shared libraries, it is advantageous to put this variable declaration and initialization in a file by itself so that the com-
piler can link it in with the shared libraries. You should consult your compiler and operating system documents for
instructions on how to create shared libraries.
594 XView Programming Manual
The xv_find() routine is unset for the logo package because it doesn’t make sense to be
able to reuse an instance of a logo object. That is, because the logo package is subclassed
from the WINDOW package, it is impossible to render a window in more than one place on the
screen at a time. It is only possible to create multiple instances of this type of object even
though the package may display the same logo image.*
This is contrary to the way the font package works, for example. Fonts can be rendered any-
where and they do not contain windows, so referencing the same font instance is reasonable.
However, the scope of availability for fonts is restricted to each server. Not all fonts may ex-
ist on all servers, and even if they do, they do not share the same XIDs. Thus, you cannot
render a string using a font in a window that resides on a server other than the server from
which the font was obtained.
The find method is discussed in detail in Section 25.9, “The Find Method,” later in this chap-
ter.
25.5.4 The Initialize Method
The initialize method is responsible for allocating an instance of the private_data struc-
ture and linking the private and public structures together. Once the public and private struc-
tures have been initialized and linked, an instance of the class has been created. However, it
is incomplete because none of the attributes of the class have been set in the new instance.
This may be done in the initialize routine and in the set routine, called later.
The function takes the following form:
int
init_func(owner, package_public, avlist)
Xv_opaque owner;
Xv_opaque *package_public;
Attr_avlist avlist;
The owner parameter is the object passed as the owner to the call to xv_create. It is de-
clared as Xv_opaque here because its actual type varies from package to package. How-
ever, the type of the owner is also a public data type. For the logo package, the owner is a
Frame since frames are used to manage subwindow layout (and the logo package is sub-
classed from the WINDOW package).
The package_public parameter is a pointer to the public data type declared in the public
header file. For the logo package, this type is Logo_public. The XView intrinsics have
allocated this data type before calling the routine.
The avlist parameter contains the attribute-value pairs specified in the call to xv_
create(). These may or may not be evaluated from within the initialize routine depending
on the nature of the attribute. We’ll get to this in a moment.
*It is possible to share the same logo image, if not the entire logo object. This can be accomplished using the Bitmap
package discussed next.
XView Internals
XView Internals 595
The function returns XV_OK or XV_ERROR depending on whether it was successful allocating
and initializing the necessary resources. If there is an error of any kind that should prevent
the object from being instantiated, all allocated resources should be freed and the function
should return XV_ERROR. If there is an error during any phase of the initialize method,
XView calls the destroy method for each package (except for the package whose initialize
routine actually returned XV_ERROR). The op parameter passed has the value DESTROY_
CLEANUP
. See Section 25.5.7, “The Destroy Method,” for details.
The following is a listing of the initialize function for the logo package:
static int
logo_init(owner, logo_public, avlist)
Xv_opaque owner;
Logo_public *logo_public;
Attr_avlist avlist; /* ignored here */
{
Logo_private *logo_private = xv_alloc(Logo_private);
Display *dpy;
Window win;
if (!logo_private)
return XV_ERROR;
dpy = (Display *)xv_get(owner, XV_DISPLAY);
win = (Window)xv_get(logo_public, XV_XID);
/* link the public to the private and vice-versa */
logo_public->private_data = (Xv_opaque)logo_private;
logo_private->public_self = (Xv_opaque)logo_public;
/* create the 1-bit deep pixmap of the X logo */
if ((logo_private->bitmap = XCreatePixmapFromBitmapData(dpy, win,
xlogo32_bits, xlogo32_width, xlogo32_height,
1, 0, 1)) == NULL) {
free(logo_private);
return XV_ERROR;
}
/* set up event handlers to get resize and repaint events */
xv_set(logo_public,
WIN_NOTIFY_SAFE_EVENT_PROC, logo_redraw,
WIN_NOTIFY_IMMEDIATE_EVENT_PROC, logo_redraw,
NULL);
return XV_OK;
}
The first thing this function does is allocate the private data structure for the logo object us-
ing the xv_alloc() macro. This macro is defined to be:
#define xv_alloc(t) ((t *)xv_calloc((unsigned)1, (unsigned)sizeof(t)))
Because xv_calloc() is used, the entire private data structure is allocated and all the
fields are initialized to NULL or 0 (thus the analogy to calloc()). The fields of the logo
data structure that must be initialized are the bitmap and the GC.
The bitmap is the X logo, a Pixmap created by XCreatePixmapFromBitmapData().
In order to create the pixmap, XCreatePixmapFromBitmapData() requires a pointer
to the Display and an X window, both of which can be obtained from the window part of
596 XView Programming Manual
the logo object. Since the initialize phase of XView initializes classes from the generic pack-
age down through subclasses, we know the logo’s parent (the WINDOW package) has already
been initialized and we can use its XID.
While we have initialized the logo’s pixmap to use, we cannot initialize the GC for the logo
because we do not know the ultimate foreground and background colors of the window.
These pixel values are extracted from the window’s colormap segment, and although the
window for the logo has been created and initialized, its cms has not been assigned yet. This
is not done until the window’s set routine is called. Since the WINDOW package does not eval-
uate the WIN_CMS attribute in its initialize routine, the logo package cannot attempt to read it
from the logo package’s initialize routine. This must be done later, after the WINDOW pack-
age’s set routine has had a chance to set the window’s cms.
Providing a practical example, consider the following code fragment:
cms = xv_create(NULL, CMS,
CMS_SIZE, 2,
CMS_NAMED_COLORS, "blue", "red", NULL,
NULL);
logo = xv_create(frame, LOGO,
WIN_CMS, cms,
NULL);
Here, the programmer intended the logo to be rendered in red with a blue background. This
is accomplished by creating a colormap segment with two colors: blue and red. During the
initialization phase of object creation, the WINDOW package creates its window, but only as-
signs a default colormap segment. It is only during the set phase that the window is assigned
the colormap segment from the
WIN_CMS attribute. Since the set phase is done in reverse or-
der (e.g., the logo’s set routine is called before its parent’s set routine), the logo package can-
not query its window’s colors until later. The only opportunity for the logo package to get
the window’s colors is during the extra call to the set routine in which XV_END_CREATE is
passed. The set routine in this case is called in ascending order (top down) and the logo can
now query its window’s colormap segment.
It is true that if the programmer specifies attribute-value pairs in the call to xv_create(),
those pairs are passed to the initialize function in the avlist parameter. However, since the
logo package has no attributes of its own for the user to specify, the avlist is ignored in
favor of allowing the other packages to deal with attributes. While we could have looked in
this attribute list for a WIN_CMS attribute and captured the pixel values from it, a parent pack-
age can override or change its mind about which attributes it actually decides to use. Al-
though this may be unlikely, the XView design allows for it to happen and, therefore, XView
packages should be written with this possibility in mind.
A general rule of thumb is that packages should not test for attributes from other packages
through the avlist. Instead, the preferred method is to use xv_get() to allow the pack-
age that is responsible for the attribute to return whatever value it deems appropriate. Note
that this is not always true—there are some cases where packages not only look for attributes
that don’t belong to them, but they override them. The PANEL package, for example, does not
allow the programmer to change the foreground and background colors on its window by in-
tercepting or modifying certain color-related attributes. The PANEL package does this in or-
der to prevent the programmer from violating OPEN LOOK.
XView Internals
XView Internals 597
On the other hand, let’s suppose we wanted to restrict the colors used by the logo window to
black and white. In this case, we would want to override the WIN_CMS specification if the
programmer provided one. We would do this by consuming the WIN_CMS attribute (and
presumably the WIN_CMS_NAME attribute) from the avlist using the ATTR_CONSUME()
macro ( see Section 25.2.5, “Consuming Attributes”). The attribute may be consumed here in
the initialize routine or later in the set routine. If the WINDOW package chose to consume
these attributes, it could have done so before we got to them. However, by consuming them
in the logo’s initialize routine, we can prevent the WINDOW package from consuming them in
its set routine called later. If an attribute that is consumed is just done to prevent another
package from evaluating it, chances are that this attribute should not have been set by the
programmer. In such a case, a warning should be dispatched via xv_error().
Finally, the last thing done in logo_initialize() is setting the event handlers for the
window. This is not intended to track events generated by the user, but to track
WIN_REPAINT (Expose) and WIN_RESIZE (ConfigureNotify) events for the logo’s
window. This is done to determine when and where the logo should be drawn.
The method used to track these events is by using the specified attributes:
xv_set(logo_public,
WIN_NOTIFY_SAFE_EVENT_PROC, logo_redraw,
WIN_NOTIFY_IMMEDIATE_EVENT_PROC, logo_redraw,
NULL);
These are private attributes (e.g., not for general programmer use) from the WINDOW package
specifically for the purpose of having the internals of XView packages be able to specify
event handlers that do not conflict with or get overridden by the programmer. The program-
mer, as you may recall, uses the attribute, WIN_EVENT_PROC to handle events destined for the
window. In fact, this attribute will continue to work as expected despite the use of the
WIN_NOTIFY_* attributes listed above.
These two private attributes are similar to the Notifier’s notify_set_event_func()
function. The programmer can interpose on the logo’s event function just as described in
Chapter 20, The Notifier, as usual. In this case, the programmer’s interposing functions are
called ahead of the logo_redraw() function (by design).
25.5.4.1 The logo_redraw() function
The logo_redraw() function itself does not have anything to do with XView internals or
package implementation. However, it is described here so as to keep the continuity of the
discussion.
This function simply renders the logo in the object’s window. It uses XCopyPlane() to
render the logo because the logo Pixmap is known to be one-bit deep whereas the logo’s
window can be any depth. This is done for the last in a possible series of Expose events as
shown:
logo_redraw(logo_public, event)
Logo_public *logo_public;
Event *event;
{
Logo_private *logo_private = LOGO_PRIVATE(logo_public);
598 XView Programming Manual
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.