Developer.com Logo Click here to support our advertisers
Click here to support our advertisers
SHOPPING
JOB BANK
CLASSIFIEDS
DIRECTORIES
REFERENCE
Online Library
LEARNING CENTER
JOURNAL
NEWS CENTRAL
DOWNLOADS
COMMUNITY
CALENDAR
ABOUT US

Journal:

Get the weekly email highlights from the most popular journal for developers!
Current issue
developer.com
developerdirect.com
htmlgoodies.com
javagoodies.com
jars.com
intranetjournal.com
javascripts.com

All Categories : Linux

developer.com - Reference
Developer.com Logo Click here to support our advertisers
Click here to support our advertisers
SHOPPING
JOB BANK
CLASSIFIEDS
DIRECTORIES
REFERENCE
Online Library
LEARNING CENTER
JOURNAL
NEWS CENTRAL
DOWNLOADS
COMMUNITY
CALENDAR
ABOUT US

Journal:

Get the weekly email highlights from the most popular journal for developers!
Current issue
developer.com
developerdirect.com
htmlgoodies.com
javagoodies.com
jars.com
intranetjournal.com
javascripts.com

Linux


- 60 -

Server Support for PEX

by Kamran Husain

IN THIS CHAPTER

  • What Is PEX?

  • PEX Server

  • Building a Server

  • Getting PEX

  • Sample PEX Source File

  • PEXlib and Motif

  • Where to Look for More Information

This chapter is really two chapters in one. I will discuss two topics here:

  • Building a new server for X.

  • To build this new server, we will add PEX support to it. This will serve as an example of how to add more capabilities to the X server.

After you read this chapter, you will have an idea of how to draw to an X drawable, and use Motif and PEX together. This chapter is not a tutorial on PEX, nor will you become the world's expert on writing additions to X servers. This chapter will introduce you to techniques that you can use to add features to the X server. You will also learn where to look for more information about PEX and X servers.

What Is PEX?

The X Window system is primarily a two-dimensional graphical system. Due to the lack of standards in the three-dimensional (3-D) area, there hasn't been an evolution of good 3-D developmental tool libraries. However, PEX is supposed to alleviate this problem by providing a consistent set of toolkit calls, which enables a user to support 3-D software with little effort.

PEX originally stood for PHIGS Extensions to X. PHIGS stands for Programmer's Hierarchical Interactive Graphics System. PEX has been adopted by the Common Open Software Environment (COSE) for X11 releases that are later than 2.2.

However, PEX is simply historical at this point, because the last version of the PEX protocol (Version 6.0) is not designed specifically for PHIGS at all. PEX is now designed to support 3-D application programs. PEX is an extension to the Core X Protocol to provide 3-D graphics support within the X Window environment. Included in the X11R5 distribution is code for the Sample Implementation of the extensions to the X Window server, which implements the functionality defined by the PEX Protocol Extensions.

In order to access the PEX functional extensions to the X server, one must use an application that generates PEX Protocol. The application can either generate the Protocol bytestream itself, or use something called an Application Protocol Interface (API). One such API provided with the X11R5 distribution is the PHIGS 3-D graphics standard. This is a port of the PHIGS C language binding onto an internal layer, which generates the PEX Protocol enabling this particular PHIGS implementation to work within the X Window environment. Other alternate APIs are available via anonymous FTP from export.lcs.mit.edu.

When discussing PEX, it is important not to confuse the protocol with the API. The API is the conceptual model of 3-D graphics that the application developer sees when developing a client program. The PEX protocol is generated by the API, and is interpreted by the X server to perform graphics requests on behalf of the client program.

One API provided with the R5 PEX-SI is a PHIGS/PHIGS-PLUS API. The PHIGS/PHIGS-PLUS standards are specified in two parts. First, a functional description explains each operation conceptually, in a language-independent manner. Second, language bindings are used to bind the particular PHIGS functions to the semantics of the language. The PEX-SI comes with an application programmer interface that conforms to the latest revision of the PHIGS/PHIGS-PLUS C language binding.

If your version of R5 is patched through patch number 22, you have a second MIT-supplied API called PEXlib. PEXlib is to the PEX protocol what Xlib is to the core X protocol. PEXlib provides an interface that is as close as possible to a one-to-one correspondence between functions and protocol requests. It is intended to be a systems programming interface (so, people developing graphics toolkits and graphics systems will implement their system on top of PEXlib). It is proposed that the PHIGS API be ported to PEXlib when PEXlib is finalized. This change would not affect programs written to the existing PHIGS API.

However, because PEXlib is intimately tied to the protocol, it is expected that there will be changes between the current PEXlib (which supports Version 5.0 and 5.1 of the PEX protocol) and the PEXlib that supports the next major version of the PEX protocol, Version 6.0. Naturally, every attempt will be made to make the changes to the API minimal. The nature of the changes from 5.1 to 6.0 are not such that every primitive will be affected; rather the changes deal with the sticky problems of subsets, multibuffering, and other issues of global rendering semantics.

PEX Server

Find out whether you have PEX available on your X server first. By default, PEX support is not built into the servers you received for Linux. The xdpyinfo command displays all the extensions supported by a server.

Output from the PEX command should contain strings of the following form:

      number of extensions:   7

      XTestExtension1

      SHAPE

      MIT-SHM

      X3D-PEX     (<-- This is the line you are looking for)

Multi-buffering

      MIT-SUNDRY-NONSTANDARD

If one of the extensions listed is X3D-PEX, your server supports PEX. If you do not see this line, you must build the server yourself.

Building a Server

To build a server that only includes the drivers you need, use the LinkKit instead of compiling the complete X system. Using the LinkKit package is much easier. The LinkKit package can be found in /usr/X386/lib/Server.

The LinkKit package contains a file called site.def for you to edit. The site.def file contains the site-specific information for your system. Edit the site.def file to define which servers you want to build, and the drivers and font renderers (programs that generate fonts for display) you want to include.


NOTE: You must run all the commands in this section as root.

Let's examine the site.def file in a bit of detail. See Listing 60.1 for the site.def file that I used to create a PEX server for my machine.

Listing 60.1. Sample site.def file.

XCOMM $XFree86: mit/server/ddx/x386/LinkKit/site.def.LK,v 2.11

     1994/04/10 05:49:56 dawes Exp $



/* Configuration file for Server Link Kit */



#ifdef BeforeVendorCF



/*

 * Change these definitions if you need to override the defaults:

 */



/*

 * HasGcc: defaults:

 *          SVR3,4:           YES

 *          Mach, 386bsd:     YES

 */

/* #define HasGcc             NO */



/*

 * HasGcc2: (should also set HasGcc)

 *        defaults:

 *          SVR3,4:           YES

 *          Mach:       YES

 *          386bsd:           NO

 */

/* #define HasGcc2            NO */



/*

 * If the link kit you are using was built with gcc2, and you are using

 * a different compiler:

 *   1. Install libgcc.a in a directory searched by your `ld'

 *   2. Set NeedLibGcc to YES

 */

#define NeedLibGcc            NO



/*

 * Uncomment this if you want to link with the Gnu malloc library

 */

/* #define GnuMalloc    YES */



/*

 * GnuMallocLib: link-time flags to include the Gnu malloc library.

 * this is only used when GnuMalloc is set to YES.

 *        defaults:

 *          386bsd:           -lgnumalloc

 *          others:           -lgmalloc

 */

/* #define GnuMallocLib       -L/usr/local/gnu -lmalloc */



/*

 * Server configuration parameters

 */



#define FontRenderers         Speedo Type1

#define X386Vga2Drivers       et4000 et3000 pvga1 gvga tvga8900 ncr \

                        compaq oak generic

#define X386Vga16Drivers      et4000 tvga8900 generic

#define X386Vga256Drivers     et4000 et3000 pvga1 gvga ati tvga8900 cirrus \

                        ncr compaq oak

#define X386Hga2Drivers       /**/

/* To enable the hga2 driver, replace the above line with the following */

/* #define X386Hga2Drivers          hga6845 */



/*

 * To include the generic banked monochrome driver in the monochrome server,

 * uncomment this with one of the following low level drivers

 *    hgc1280           [Hyundai HGC-1280 1280x1024]

 *    sigma       [Sigma L-View]

 *    visa        [???]

 *    apollo            [???]

 *    ...

 *    (list is subject to grow)

 */

/* #define X386Bdm2Drivers    hgc1280 sigma visa apollo */



/* #define XF86S3Drivers            mmio_928 s3_generic */

/*

 * Set which servers to build.  Change the YES to NO for servers you don't

 * want to build.

 */



/* The SVGA color server */

#define XF86SVGAServer        YES



/* The 16-color VGA server */

#define XF86VGA16Server       NO



/* The VGA mono server */

#define XF86MonoServer        NO



/* The S3 server */

#define XF86S3Server          NO



/* The IBM 8514/A server */

#define XF86I8514Server       NO



/* The Mach8 server */

#define XF86Mach8Server       NO



/* The Mach32 server */

#define XF86Mach32Server      NO



/* Set the default server (ie the one that gets the sym-link to "X") */

/* #define XFree86DefaultServer     XF86_S3 */



/*

 * If you want PEX (and this link kit was built with PEX support), uncomment

 * the following

 */

/* #define BuildPexExt        YES */

#define BuildPexExt           YES



#endif /* BeforeVendorCF */



#ifdef AfterVendorCF



/* If you are using a different ProjectRoot, set it here */



/*

#ifdef ProjectRoot

#undef ProjectRoot

#endif

#define ProjectRoot /usr/X11R5

*/



#endif /* AfterVendorCF */

Note the following items about this site.def file:

  • The HasGcc and HasGcc2 definitions have been commented out for Linux.

  • If the LinkKit was built with gcc-2.x and you are using some other compiler, you must install libgcc.a and set NeedLibGcc to YES.

For Linux, NeedLibGcc is set to NO.

The servers are available to you via LinkKit are shown in Table 60.1. To create any of these servers, you have to set value of the corresponding variable to YES:

Table 60.1. Server types in site.def.
Server Type Variable to Set
256-color server XF86SVGAServer
256-color server XF86SVGAServer
16-color server XF86VGA16Server
Monochrome server XF86MonoServer
S3 server XF86S3Server
Mach8 server XF86Mach8Server
Mach32 server XF86Mach32Server
IBM 8514/A server XF86I8514Server

In the sample site.def in Listing 60.1, I have set only the 256-color SVGA server to be built. All other servers will not be built.


NOTE: The PEX extensions you have do not support the Monochrome server.

The Drivers variables define the video drivers that you want to include in a server. The order of drivers determines the order in which the server probes the video card to determine which driver to use. The generic driver should be the last one included in the monochrome and 16-color servers because its probe always succeeds.

The generic_s3 driver should be the last one included in the S3 servers for similar reasons.

After you have edited the site.def file, you must create the Makefile.

To build the Makefile, run this command:

# ./mkmf

Then, run make to link the servers that you have configured in the site.def file. This command takes a while. After this command is done, run the make install command to install the new servers:

#  make install


TIP: Run make clean to remove the files that were created by this procedure. This frees the directory structures of any unnecessary files, which is important because disk space is at a premium under Linux.

Now start X, run the window manager, and in an xterm use the xdpyinfo command to see whether the PEX extensions are there. It is possible to see which drivers are included in the server by running the X server with the -showconfig flag.

Writing Your Own Driver

If you are including a driver that it not part of the standard distribution, make a directory in drivers/vga256 (drivers/vga2 if it is for the monochrome server; drivers/vga16 if it is for the 16-color server; or drivers/bdm2 if it is for the bdm2 monochrome server's bdm2 screen). Copy either the source or the .o file, and a suitable Imakefile, into that directory. The name of the directory should be the same as the name of the driver. If you are adding an additional font renderer, put the library in ./renderers. Look at the VGADriver.Doc file for more details.

Getting PEX

You have PEX files on the CD-ROM at the back of this book.

There are several examples of PEX code available on the Internet. One sample library can be found at the site export.lcs.mit.edu in the /R5contrib/R5contrib-fixes directory as the file PEX.examples.tar.Z.


NOTE: For Tk and Tcl users, PEXtk is available directly from export.mit.lcs.edu, and is located in /contrib. The files are pextk.PS.tar.Z, pextk.README, and pextk.tar.Z. PEXtk uses X as its windowing system, so the UI is X-based.

Sample PEX Source File

Let's look at an example of a simple PEX program that prints the line Howdy World. (Hello World is a bit overused.) The following is the listing for printing this line:

#include "phigs/phigs.h"

#include "X11/Xlib.h"

#include "X11/Xatom.h"

#include "strings.h"



char windowName[] = "PEX in Linux";

char HelloStr[] = "Howdy World";



main()

{

      Pconnid_x_drawable      connid;

      Display                  *display;

      int                  screen;

      Ppoint                  text_pt;



        popen_phigs(NULL,0); /* open a conn. to PHIGS server */

            /*

            ** Set the error file name to NULL

            ** Set default memory size to zero

            */



      connid.display = display = XOpenDisplay( NULL );

      screen = DefaultScreen( display );

      connid.drawable_id =

         XCreateSimpleWindow( display,

             RootWindow( display, screen ),

             0, 0, 600, 600, 4,

             WhitePixel( display, screen ),

             BlackPixel( display, screen ) );



      XChangeProperty( display, connid.drawable_id, XA_WM_NAME,

          XA_STRING, 8, PropModeReplace,

          (unsigned char *) windowName , strlen(windowName) );



      XMapWindow( display, connid.drawable_id );



      popen_ws( 1, &connid, phigs_ws_type_x_drawable );



      popen_struct( 1 );



      text_pt.x = 0.2;

      text_pt.y = 0.5;

      pset_char_ht( 0.05 );

      ptext( &text_pt, HelloStr, strlen(HelloStr)): 

      pclose_struct( );



      ppost_struct( 1, 1, 1.0 );



      printf("Hit return to exit");

      getchar();



      pclose_ws( 1 );

      pclose_phigs( );

}

The first executable line in this file opens a connection to the PEX server with a call to popen_phigs(NULL,0). The NULL parameter sets the error filename to nothing, and the 0 sets the default memory size to 0.

The next lines set the display, screen, and window IDs for this application. The window ID is set to point to the root window for the application with a call to the XCreateSimpleWindow function. The display and screen IDs are set to the defaults. Note that you are using low-level X Window system function calls to create the root window. This example tells you that it's possible to access all the low-level X Window functions, in addition to the PEX functions.

The XChangeProperty function call sets the window name to the one desired. The display and window ID (connid.drawable_id) are set to that of the root window of the application.

The XMapWindow function maps your display to the current window ID.

The popen_ws() call opens the workspace for the display for you to be able to draw on. You then set the test position for the Howdy World string. Then, open a structure for writing with PEX primitives to set the text_pt structure with the text. It is necessary to call the pclose_struct() function when done with the drawing area buffer. Lastly, post the structure to ppost_struct.

Wait until the user gives the keystroke you want, and then end the application. In this case, you must call two functions before ending the application. One is a call to pclose_ws( 1 ) for closing the workspace; the other is a call to pclose_phigs( ) for shutting down the PEX server.

PEXlib and Motif

In the previous example, the drawable was used to create the drawing patterns on a drawing area widget. PEXlib by itself is intended to be an interface into the lower-level Xlib. PEXlib gives you the capability to do 3-D mappings, shading, and so on, along with other geometric transformations.

This section covers the basic act of combining PEXlib with Motif. This way, you can get a drawable area under Motif and be able to use PEX functions on it. In addition to this, you still have the Motif framework to add your own menus to it. Here are the steps to combine Motif and PEXlib:

  • Initialize an X Window, and get the best visual you can for PEX.

  • Initialize PEX with a call to PEXInitialize.

  • Create a top-level shell.

  • Create a drawing area interface for PEX.

  • Map the drawing area to the screen.

  • Create a PEX renderer (just like the GC) for this drawing area.

  • Draw to your heart's delight.

Initializing the Toolkit

For initializing the toolkit, you must use a long method instead of XtAppInitialize. This long method enables you to select the best visual you can get for PEX. The following code segment will suffice:

XtToolkitInitialize();

app_context = XtCreateApplicationContext();

cp_argc     = argc;

argv_sz = argc * sizeof(char *);

cp_argv = (char **)XtMalloc(argv_sz);

memcpy(cp_argv, argv, argv_sz); /* copy the pointers */



display = XtOpenDisplay(app_context,

            argv[0], argv[0],

            "pEX", /* Class Name */

            NULL, 0, /* no resource options */

            &argc, argv);

     

if (display == (Display *) NULL)



      abort("Unable to open display");

You are making a copy of argc and argv to preserve their values, because the call to XtOpenDisplay() mangles these original values. It's necessary to check whether the display pointer is set to a valid value when you return from XtOpenDisplay() because the display may not have been opened for various reasons, and you do not want to work a NULL pointer for the display.

Initialize the PEXlib functions with a call to the function PEXInitialize(). The syntax for this call is as follows:

#include <X11/PEX5/PEXlib.h>



int PEXInitialize(Display *dp,

      PEXExtensionInfo *info_ptr,

      int message_length,

      char *msg);

The PEXExtensionInfo pointer should point to a structure to which you want this function to return information about the PEX server. The message array should be about 80 characters long, and contain the text for any returned error messages. The function returns 0 if no errors occurred; otherwise, it returns one of the following values:

  • PEXBadExtension if the X server does not support PEX

  • PEXBadProtocolVersion if your X server and the PEXlib you are using are of different versions

  • PEXBadLocalAlloc if you are out of memory


  • PEXBadFloatConversio
    if the X server does not support the PEX floating point

Also, note that I used PEX5 as the location of the include files. When PEX 6.0 comes along, you may have to change this PEX5 reference to PEX6 in all the code you have to date. A bummer indeed, but necessary for an upgrade.

The returned PEXExtensionInfo structure is of the following form:

typedef struct {

unsigned_short    major_version;

unsigned_short    minor_version;

unsigned long release;

unsigned long subset_info;

char *vendor_name;

int   major_opcode;

int   first_event;

int   first_error;

} PEXExtensionInfo;

The major version is usually 5 or 6, and the minor version either 0 or 1. The vendor name and release are vendor-specific. The subset information contains information about the features in your PEX server, and can have the following values:
PEXImmediateMode Enables drawing primitives that are sent directly to the display.
PEXWorkstationOnly Enables workstation resources.
PEXStructureMode Enables drawing primitives to be stored in a structure before being sent to the display.
PEXCompeleteImplementation Enables all of these functions.
Check this value to see what features your X server supports. If your server does not have either the complete or Immediate mode graphics, (the Linux server is and should be complete), you should exit the application with an error message.

Creating the Window

Now create the window with the colormap and the best visual for PEX. The way to do this is as follows:

XStandardColormap       colormap;

Colormap    PEX_colormap;

     

/* open display as before */

     

screen = DefaultScreen(display);

visual = DefaultVisual(display,screen); 

depth  = DefaultDepth(display,screen); 

status = GetStdColormap(display, screen,

            visual, depth,

            &colormap);

if (status == True)

      PEX_colormap = colormap;





blue = AllocNamedColor(display, PEX_colormap,

      "Blue", 0L);



white = AllocNamedColor(display, PEX_colormap,

      "White", 0L);



     

n = 0;

XtSetArg(args[n],XmNvisual, visual); n++;

XtSetArg(args[n],XmNdepth, depth); n++;

XtSetArg(args[n],XmNcolormap, colormap); n++;

XtSetArg(args[n],XmNallowResize, True); n++;

XtSetArg(args[n],XmNmapWhenManaged, False); n++;

XtSetArg(args[n],XmNbackground, blue); n++;

XtSetArg(args[n],XmNforeground, white); n++;

XtSetArg(args[n],XmNargc, cp_argc); n++;

XtSetArg(args[n],XmNargv, cp_argv); n++;

XtSetArg(args[n],XmNheight, 400); n++;

XtSetArg(args[n],XmNwidth, 400); n++;

     

toplevel = XtAppCreateShell(NULL, "peX",

      applicationShellWidgetClass, display, args, n);





mainWindow = XmCreateMainWindow(toplevel, "mainWin", NULL, 0);



drawMe = XmCreateDrawingArea(mainWindow,



            "pexdraw", args, n);


TIP: If you are unfamiliar with programming in Motif or X, refer to Chapter 34, "Motif Programming."

The application requires the toplevel shell. For this shell, you have to manually set its visual, screen, display, and colormap. Note that the resize resource is set to True and mapWhenManaged is set to False. You have to set these values via the XtArgs args array at creation time for this to work. The toplevel shell is where you create the main window to place your Motif widgets. After you have created the main window with the XmCreateMainWindow function call, you create the drawing area called drawMe on top of this window.

Next, you add callbacks to the drawing area widget to allow for redrawing. Add the callbacks to the drawing area for the following types of events: resize, expose, and input.

The complete code for a very simple application is shown in Listing 60.2.

Listing 60.2. A sample PEX application with Motif.



#include <Xm/Xm.h>

#include <Xm/DrawingA.h>

#include <Xm/MainW.h>

#include <Xm/RowColumn.h>

#include <X11/PEX5/PEXlib.h>

#include <stdio.h>



int bailout(char *str)

{

printf ("\n %s", str);

exit(1);

}



int pex_set_line_color(Display *dpy, PEXRenderer p,

      float r, float g, float b)

{

PEXColor pc;



pc.rgb.red = r;

pc.rgb.green = g;

pc.rgb.blue = b;



PEXSetLineColor(dpy, p, PEXOCRender, PEXColorTypeRGB, &pc);

}



void doSamplePEX( Display *dpy, Window win, PEXRenderer ren)

{

PEXCoord    coords[10];



PEXBeginRendering(dpy, win, ren);



PEXSetLineWidth(dpy, ren, PEXOCRender, 8.0);



pex_set_line_color(dpy, ren, 0.5, 0.5, 1.0);



coords[0].x = 0.3; coords[0].y = 0.3; coords[0].z = 0.0;

coords[1].x = 0.3; coords[1].y = 0.6; coords[1].z = 0.0;

coords[2].x = 0.6; coords[2].y = 0.6; coords[2].z = 0.0;

coords[3].x = 0.6; coords[3].y = 0.3; coords[3].z = 0.0;



PEXPolyline(dpy, ren, PEXOCRender, 4, coords);



pex_set_line_color(dpy, ren, 1.5, 0.5, 1.5);



coords[0].x = 0.3; coords[0].y = 0.3; coords[0].z = 0.5;

coords[1].x = 0.3; coords[1].y = 0.6; coords[1].z = 0.5;

coords[2].x = 0.6; coords[2].y = 0.6; coords[2].z = 0.5;

coords[3].x = 0.6; coords[3].y = 0.3; coords[3].z = 0.5;



PEXPolyline(dpy, ren, PEXOCRender, 4, coords);



PEXEndRendering(dpy, win, ren);

XFlush(dpy); /* important */



}





void quitBtn( Widget w, void *p, void *pp)

{

      exit(0);

}





void drawBtn( Widget w, XmDrawingAreaCallbackStruct *sp,

            XtPointer *client_data)

{

      Dimension   wd, ht;

      PEXRenderer *rp;



      if (sp == NULL) return;



      switch(sp->reason)

      {

      case XmCR_EXPOSE:

            if (sp->event->xexpose.count == 0)

            {

            rp = (PEXRenderer *)client_data;

            doSamplePEX(XtDisplay(w), XtWindow(w), *rp);

            }

            break;

      case XmCR_INPUT:

            break;

      }

}



int

pexInit(Display *dpy, PEXExtensionInfo **pexparms)

{

int   err;

char  errorMsg[PEXErrorStringLength+1];

PEXExtensionInfo *pex_info;



      err = PEXInitialize(dpy, pexparms,

            PEXErrorStringLength, errorMsg);



      if (err) return False;

     

      pex_info = (PEXExtensionInfo *)(*pexparms);



      if( (pex_info->subset_info & PEXImmediateMode) ||

      ((pex_info->subset_info & 0xffff) == PEXCompleteImplementation))

      {

      return True;

      }



      return False;

}



int main(int argc, char *argv[])

{

      Widget parent;   

      XtAppContext      app_context;

      int cp_size;

      int cp_argc;     

      int cp_argv;     

      int status;

      int screen;

      int depth;

      int fore;

      int bkg;

      int n;

      Arg wars[20];

      Visual *visual;

      Colormap colormap;

      XStandardColormap std_cmp;

      PEXRendererAttributes pex_attr;

      Display     *dpy;

      PEXExtensionInfo *pexParms;

      PEXRenderer  ren;

      Widget mainw;

      Widget filemenu;

      Widget menubar;

      Widget exitBtn;

      Widget drawme;





      XtToolkitInitialize();

      app_context = XtCreateApplicationContext();



      cp_argc = argc;

      cp_size = argc * (sizeof(char *));

      cp_argv = (char **)XtMalloc(cp_size);

      memcpy(cp_argv, argv, cp_size);



      dpy = XtOpenDisplay(app_context, NULL, NULL,

            "pexSample", NULL, 0, &argc, argv);



      if (dpy == (Display *) NULL)

            bailout("Cannot open display");



      status = pexInit(dpy,&pexParms);

      if (status == False) bailout("Cannot use PEX");





      screen = DefaultScreen(dpy);

      visual = DefaultVisual(dpy, screen);

      depth =  DefaultDepth(dpy,screen);



      status = GetStdColormap(dpy, screen, visual, depth, &std_cmp);

      colormap = std_cmp.colormap;

      bkg = BlackPixel(dpy,screen); 

      fore = WhitePixel(dpy,screen);

     



      n = 0;

      XtSetArg(wars[n], XmNvisual, visual); n++;

      XtSetArg(wars[n], XmNdepth, depth); n++;

      XtSetArg(wars[n], XmNcolormap, colormap); n++;

      XtSetArg(wars[n], XmNbackground, bkg); n++;

      XtSetArg(wars[n], XmNborderColor, fore); n++;

      XtSetArg(wars[n], XmNargc, cp_argc); n++;

      XtSetArg(wars[n], XmNargv,cp_argv); n++;

      XtSetArg(wars[n], XmNallowResize, True); n++;

      XtSetArg(wars[n], XmNmappedWhenManaged, False); n++;

      XtSetArg(wars[n], XmNwidth, 300); n++;

      XtSetArg(wars[n], XmNheight, 300); n++;

      parent = XtAppCreateShell(NULL,"pexSample",

            applicationShellWidgetClass, dpy, wars, n);



      n = 0;

      mainw = XmCreateMainWindow(parent, "mainwindow", wars, n);



      n = 0;

      XtSetArg(wars[n], XmNresizePolicy, XmRESIZE_ANY); n++;

      XtSetArg(wars[n], XmNbackground, bkg); n++;

      XtSetArg(wars[n], XmNborderColor, fore); n++;

     

      drawme = XmCreateDrawingArea(mainw, "da", wars, n);



      XtAddCallback(drawme, XmNexposeCallback,

      (XtCallbackProc)drawBtn, (XtPointer) &ren); 

      XtAddCallback(drawme, XmNinputCallback,

      (XtCallbackProc)drawBtn, (XtPointer) &ren); 

      XtAddCallback(drawme, XmNresizeCallback,

      (XtCallbackProc)drawBtn, (XtPointer) &ren); 



      XtManageChild(drawme);

      XtManageChild(mainw);

      XtRealizeWidget(parent);

     

      pex_set_color_approx(dpy,XtWindow(drawme), &std_cmp, &pex_attr);



      XtMapWidget(parent); 



      ren = PEXCreateRenderer(XtDisplay(mainw), XtWindow(drawme), 

            PEXRAColorApproxTable, &pex_attr);

      if (ren == 0) {

            printf("\n Bad renderer \n"); exit (1);

      }

     

      XtAppMainLoop(app_context);

      return(0);

     

}

A few points to note about Listing 60.2 are that the immediate mode was used for rendering on the screen. PEX-SI provides no support for double buffering. This is a serious bug because lack of double buffering hinders performance.

Even worse, the PEX-SI API assumes that the client desires an XClearArea on the window before each frame is drawn. This causes unnecessary flickering while the screen is cleared and redrawn on all primitive drawing calls. What should have been done was to provide an end-of-render procedure hook, with the default hook installed to do a clear area function call.

Individual vendors (because of market pressure) have provided their own solutions to the double buffering problem. (Most PHIGS workstations do double buffering. If you do immediate mode you get single buffering along with the PEX-SI's XClearArea call.)

A final word about adding too many features in an X server. The more you add to the X server, the more memory it chews up in your system. Unless you absolutely require PEX (or other) support, do not add it to your X server, especially if RAM is 8MB or less. The PEX support for Linux added about 420KB on my system, which is not a lot, but it does start adding up. Also, the overhead of PEX applications tend to make my 8MB, 486/33 somewhat slow when running PEX demos, which leads me to believe that PEX on Linux with less than 16MB is not worth the hassle. If you are serious about PEX on Linux, get a faster machine and put gobs of memory on it. The performance improved very dramatically on a 486/66 with 32MB of RAM.

Where to Look for More Information

If you would like more information and examples of source code for PEX, check out these FTP sites:

  • export.lcs.mit.edu in /R5contrib/contrib-R5fixes has several tar files of source code for PHIGS and PEX including a 3-D drawing program.

  • http://www.x.org is a good place to start looking for more information on X.

Summary

This chapter has been a whirlwind tour of PEX. The topic of PEX could be a book in itself. In fact, there are several texts available that go into excruciating detail about PEX. You should have learned the following information from this chapter:

  • How to create a new X server with your specifications. Building your own server with LinkKit is far easier than trying to re-create the entire X distribution. There are fewer memory requirements, and the build takes up less disk space and time to compile and link.

  • How to install the new server. The LinkKit does this for you automatically and gives you options to clean your directories, and so on.

  • How to check for the extensions in the current server.

  • How to interface Motif with PEX.

  • The trade-offs of having too many extensions in X server, such as loss of memory and speed for added functionality.

  • Where to look for more information about PEX and Linux.
Ruler image
Contact
reference@developer.com with questions or comments.
Copyright 1998 EarthWeb Inc., All rights reserved.
PLEASE READ THE ACCEPTABLE USAGE STATEMENT.
Copyright 1998 Macmillan Computer Publishing. All rights reserved.
Click here for more info

Click here for more info