25.4 XView Packages
Earlier, we introduced the concept of XView methods and how they are used to define the in-
teraction between a particular class and the XView intrinsics. These methods, along with a
set of attributes, macros, types, and functions, collectively make up an XView package. The
XView library is made up of statically subclassed (pre-built) packages representing user in-
terface objects.
25.4.1 The Xv_pkg Type
Packages (and thus, classes) are declared by creating a global variable of type Xv_pkg. This
package is defined in <xview/pkg_public.h> as:
typedef struct _xview_pkg {
char *name;
Attr_attribute attr_id;
unsigned size_of_object;
struct _xview_pkg *parent_pkg;
int (*init)();
Xv_opaque (*set)();
Xv_opaque (*get)();
int (*destroy)();
Xv_object (*find)();
} Xv_pkg;
The fields of the Xv_pkg type are declared and used as follows:
name The name of the package is a unique, descriptive string. This is useful
for debugging the ERROR package, and it may also be used in the fu-
ture to implement resource handling from the resource database.
Therefore, it should not contain whitespace or dots (periods). Under-
scores and hyphens are allowed, but should be avoided for aesthetic
reasons. A combination of uppercase and lowercase letters should be
used to imply multi-word names (e.g., “DigitalClock”).
attr_id This is the ID of the package. It is set to a unique number and is used
in attributes’ values to associate them with the corresponding pack-
age. For XView extensions (packages you write), the value should lie
between the value for ATTR_PKG_UNUSED_FIRST and the value for
ATTR_PKG_UNUSED_LAST.
size_of_object This is the size of the public part of the object. XView objects are
broken down into a public part and a private part. XView is responsi-
ble for allocating the public part, while the initialize method is re-
sponsible for allocating the private part. The value of the
size_of_object field is used by the XView intrinsics to know
how much space to allocate when creating a new instance of the pub-
lic part from this class.
parent_pkg This is a pointer to package’s parent (the package above the object in
the object hierarchy).
XView Internals
XView Internals 589
init This is the initialize method for the package. It is a pointer to a func-
tion that returns an error status (XV_OK or XV_ERROR) depending on
whether the initialization process was successful in creating an in-
stance of the object.
set This is the set method. This is a pointer to a function that is called
when the programmer calls xv_set(). The function typically re-
turns an error status (XV_OK or XV_ERROR) but may return an opaque
data type if it chooses.
get This is the get method. This is a pointer to a function that is called
when the programmer calls xv_get(). The function returns the val-
ue of the attribute specified in the call to xv_get(). A status value
may be set indicating an error.
destroy This is the destroy method; it is a pointer to a function that is called
when the object is destroyed via xv_destroy() or when the win-
dow manager invokes it in a “save yourself” operation (discussed lat-
er). When an object is being destroyed, the function frees any allocat-
ed fields of the private data structure. The function returns either
XV_OK or XV_ERROR.
find The find method is a pointer to a function that returns a handle to an
existing instance of the package specified to xv_find(). If no in-
stances of the package with the specified attributes can be found,
NULL is returned and XView may call the initialize routine depending
on the value of XV_AUTO_CREATE.
Details about the form of the functions listed above are given later in Section 25.5.2, “The
Implementation File.”
25.4.2 Public and Private Data
In XView, the object that is made available to the programmer writing XView applications is
a public data type defined in the public header file for the package. The only information this
type contains is a handle to two data types: the object’s parent-data type and the private data.
The public data type is what xv_create() returns to the user. Its nature will become clear
in the sample XView package we create later.
The parent data is the public data type of the parent package (the superclass). The private
data type is used by the implementation of the XView class. In it, there is a pointer to an ob-
ject that contains specific information about the object itself. This may include a window,
boolean variables, other data structures, and so on. It also contains a pointer back to the pub-
lic data type.
The initialize routine allocates and initializes the fields within the private data type. The ini-
tialize routine is also responsible for setting the handles of the public and private data types
to one another. Once this double-linking occurs, an instance of the class is complete and the
XView intrinsics return a handle to the public type. This is discussed in detail later in Sec-
tion 25.5.4, “The Initialize Method.”
590 XView Programming Manual
25.5 The Logo Package
This section presents an implementation for a simple package utilizing the concepts intro-
duced so far. This example may help explain some of the more confusing concepts for those
still unsure of the material presented.
The example package is called logo. All this object does is draw the X logo in the middle of
a window. To do this, we require a window, the Pixmap containing the X logo, and a GC to
specify the colors to use when rendering the pixmap. Creating a window is a very compli-
cated task; there’s so much to worry about with colormaps, visuals, displays, and screens.
Since the XView WINDOW package already handles this, the logo class is subclassed from it to
take advantage of the WINDOW package’s capabilities. That package can handle all the win-
dow-related details without intervention from the logo package. More generic attributes such
as the geometry and position of the object are handled by the GENERIC package.
The only thing the logo package needs to concern itself with is providing the data for the bit-
map showing the X logo. Once we have that, all we need to do is render it to the window
when repaint or Expose events take place.
25.5.1 Header Files
Packages usually contain two header files (or include files): one that is included by applica-
tions that intend to use the package, and another that is included by the source code that im-
plements the package itself.
25.5.1.1 The public header file
The file logo.h is the public header file for the logo package.
/* logo.h -- public header file for the logo XView class. */
#include <xview/xview.h>
#include <xview/window.h>
extern Xv_pkg logo_pkg;
#define LOGO &logo_pkg
typedef Xv_opaque Logo;
typedef struct {
Xv_window_struct parent_data;
Xv_opaque private_data;
} Logo_public;
Since the logo package is subclassed from the WINDOW package, we must include <xview/win-
dow.h>. We can’t include that file unless we include <xview/xview.h> first. You’ll find that
most packages include at least the basic XView header files.
Next, we declare the logo_pkg object as an external variable of type Xv_pkg *. This is a
global variable that we must declare later in the implementation source file where the private
data is declared. The LOGO definition refers to the address of this global variable. The Logo
XView Internals
XView Internals 591
type is a typedef of Xv_opaque. This is basically a convenience type for the benefit of the
programmer and follows the style of the other XView packages.
With the #define of LOGO and the declaration of the Logo type, the necessary types are
available to make it possible for the programmer to create an instance of the logo object:
Logo logo;
logo = xv_create(parent, LOGO, NULL);
For the simple logo package, this is all that is necessary to declare in the public header file.
There are no attributes specific to the logo package. Had we wanted to provide attributes,
their declarations would be here in the public header file. We’ll add attributes to the logo
package later in the chapter.
The parent parameter in the call to xv_create() for a logo object must be a Frame be-
cause the logo is subclassed from the WINDOW package. This is because the FRAME package is
the only one that manages subwindow layout.
Finally, the last thing declared in the public header file is the public data type, Logo_
public. This is the actual object returned by xv_create(). Since the programmer has
no need to reference fields in this data type, an opaque data type is sufficient. Therefore, the
programmer uses the Logo type.
The Logo_public structure has the two fields discussed earlier: a handle to the parent ob-
ject and a pointer to the private data. The parent handle is a public data type similar to the
logo’s public data type. In this case, the public data type for the parent object is Xv_
window_struct. We use the real data type for this rather than the opaque type, Xv_
Window, because XView needs to reference internal fields within it.
The private_data field is a pointer to the actual data structure used by the internals of
the logo object. But in the spirit of true object-oriented programming, this type is hidden
from the programmer by declaring it to be Xv_opaque.
25.5.1.2 The private header file
The primary purpose of the private header file is to declare the private data structure men-
tioned above. This file is named with the _impl.h suffix implying that it is used by the code
that implements the logo object methods. Here is the logo_impl.h file for the logo package:
/* logo_impl.h -- implementation-dependent header file for the
* logo XView class.
*/
#include "logo.h"
typedef struct {
Xv_object public_self; /* pointer back to self */
GC gc; /* GC to render logo */
Pixmap bitmap; /* xlogo bitmap */
} Logo_private;
#define LOGO_PUBLIC(item) XV_PUBLIC(item)
#define LOGO_PRIVATE(item) XV_PRIVATE(Logo_private, Logo_public, item)
592 XView Programming Manual
The public header file is always included in the private header file since it has all the neces-
sary declarations specific to the package and it includes other header files that may be need-
ed.
The private logo structure is declared next. The first field in all private data structures is a
handle back to the public data structure. Again, when the initialize routine for the package is
called, an instance of the private data type is allocated and its public_self field is set to
the public data type passed. This is shown in Section 25.5.4, “The Initialize Method.”
The rest of the fields in the private data structure are those that are specific to the aspects of
the logo package that vary from instance to instance. This includes a handle to a Pixmap
(which is the X logo bitmap) and a GC. When multiple instances of the object are created,
each instance uses a discrete pixmap and GC since each instance of the class may have differ-
ent window attributes. That is, the programmer may create a logo on a color window and an-
other logo for a monochrome window.
A general rule of thumb is that there should be few, if any, global variables in the implemen-
tation of a package. These variables should almost always be declared as fields within the
private data type. Therefore, all variables that are needed by the package and that may have
different values depending on the instance are declared as fields within the logo’s private
data structure.
The last two lines of the private header file are:
#define LOGO_PUBLIC(item) XV_PUBLIC(item)
#define LOGO_PRIVATE(item) \
XV_PRIVATE(Logo_private, Logo_public, item)
These macros are used to facilitate the task of cross referencing to and from the public and
private data types. Because these types are declared as Xv_opaque, typecasting is neces-
sary to coerce the type into a data type needed. They utilize the two XView macros,
XV_PUBLIC and XV_PRIVATE. These macros are defined in <xview/pkg.h> as:
#define XV_PRIVATE(private_type, public_type, obj) \
((private_type *)((public_type *) (obj))->private_data)
#define XV_PUBLIC(obj) ((obj)->public_self)
These macros are used frequently in source files that implement an XView package.
25.5.2 The Implementation File
The next task is to declare the logo package and to implement all the methods. This may be
done in one or more source files. For maintenance, it is much easier to declare as much as
possible in one file and declare all functions as static. This is to insure that the functions
used by the package are used only by the package. However, in the event that more than one
file is used to contain all the functions necessary to implement a package, it is impossible to
restrict the scope of a function in this manner. XView, therefore, introduces two reserved
types that can be used to declare functions for either internal (private) use or public use.
XView Internals
XView Internals 593

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

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.