Department of Engineering

IT Services

Programming Tips

Catching Exposure Events

If a window is obscured and then subsequently uncovered it is the clients responsibility to do any repainting which may be needed. X merely sends the correct event type and then leaves it to the application to decide what to do about it. The usual solution is to have a subroutine for redrawing the window which is called whenever the expose events are delivered.

No drawing happens until the first expose event arrives. Ensure that all windows receiving events appear on screen after events have been selected but before events happen. Otherwise the first expose event might be missed.

Avoiding multiple Exposure

You don't want to redraw the window more than is necessary. If a window receives 2 expose events and nothing happens in between, the window needn't be drawn twice. Strategies are

  • Ignore all Expose events whose count field isn't zero.
  • Since all expose events generated by a single user action are guarenteed to be contiguous in the queue, you can discard all but the first.

If you want to remove all expose events relating to a certain window, use

XEvent event;
...
case Expose:
  /* deal with event */
  while XCheckTypedWindowEvent(display,window,Expose,&event)
        ;

Coping with Exposures

You will have to repair the damage made by occluding windows. Some options are

Display lists:-
keep a note of all graphics operations and replay them when necessary.

Backing Store:-
If your machine supports it (use xdpyinfo from the command line to find out) you could set this facility, but it will tie memory up.

Exposure Events:-
the event returns region affected, so you could just redraw this area. Eg, a chessboard could just have damaged squares redrawn.

Clipping using Regions:-
redraw only the damaged regions by clipping.
XEvent event;
Region region;
XRectangle rectangle;
switch(event.type){
     case Expose:
         region = XCreateRegion();
 
         /*Make the union of the rectangles into a  Region */
         do{
           rectangle.x = (short) event.xexpose.x
           rectangle.y = (short) event.xexpose.y
           rectangle.width = (unsigned short) event.xexpose.width
           rectangle.height = (unsigned short) event.xexpose.height
           XUnionRectWithRegion(&rectangle,region,region);
 
         } while(XCheckTypedEvent(display,Expose, &event);
          
         XSetRegion(display,gc,region);
         redraw(window);
         XDestroyRegion(region);
         break;

Catching Motion Events

These can come in thick and fast. If you find that you can't process them fast enough, try using PointerMotionHintMask. This modifies the effect of other `Pointer Motion' events that you have selected. If the pointer starts moving then only one event will be generated until a button or key changes state or XQueryPointer is called.

Getting arguments

To get a value from .Xdefaults use

char* XGetDefault(display,program_name, option)
char *program_name;
char *option;

To parse a geometry string, use

int XGetGeometry(geometry,x,y,width,height);
   int *x,*y;   /*RETURN */
   unsigned int *width, *height;  /*RETURN*/

The bits in the returned integer show how many values have been returned. The bits are XValue,YValue, WidthValue, HeightValue, XNegative and YNegative.

If you are likely to have many possible command line arguments, use XrmInitialise() to initialise a resource manager, then

XrmDatabase XrmGetFileDatabase(resource_file)
char *resource_file;

This will create a database from a file than has a format like .Xdefaults. To merge in any arguments on the command line, use

void XrmParseCommand(db,table, table_length, prog_name, argc, argv);
XrmDatabase db;
XrmOptionDescList table; /* a table of possible options */
int table_length;
char *prog_name; 
int *argc /* supplies the number of arguments, returns number unprocessed*/
char **argv;  /* supplies arguments, returns those unprocessed */

table is a pointer to an array of structures of the following type

typedef struct {
   char *option;          /* the command line flag */
   char *resouce;         /* the .X11defaults style string */
   XrmOptionKind argkind; /* XrmoptionSepArg, XrmoptionStickyArg,etc
                             (see /usr/include/X11/Xresource.h  */
   caddr_t value;         /* what to use if argkind is XrmoptionNoArg
                             (use NULL otherwise) */
} XrmOptionDescRec

Colors

There's no way of telling how many colorcells are unallocated.

Your program should work on both monochrome and color screens if possible using something like the following code.

Bool iscolor;
Xcolor blue;
iscolor = (XDisplayCells(display, screen)>2);
foreground = (iscolor &&
              XParsecolor(display,cmap, "blue",&blue) &&
              XAllocColor(display,cmap, &blue))
                    ? blue.pixel : BlackPixel (display,screen));

Errors

There is no need for a client program to provide its own error handlers as default handlers exist and these are used automatically if the user does not request otherwise. If you do want your own handlers they can be declared to the X server using these routines. Look out for Bad Match, which means your arguments don't match up with each other.

char *XDisplayName(string)/* reports an error when the requested display
                             doesn't exist */
char *string /* if NULL, it looks in the enviroment and returns the 
                display name that the user was requesting. */


XIOErrorHandler( handler ) /*specify hander for FATAL errors  */
    int handler(Display *);/* user supplied handler routine */
                           /* should not return             */

XSetErrorHandler( handler )/* specify handler for NONFATAL errors */
    int handler(Display *, XErrorEvent *)
             /* user supplied handler is passed error event */

XSetIOErrorHandler( handler )/* specify handler for NONFATAL errors */
    int handler(Display *)
             /* user supplied handler is passed error event */

typedef struct _XErrorEvent
{
    int serial;        /* serial number of failed request  */
    char error_code;    /* error code of failed request     */
    char request_code;  /* Major op-code of failed request   */
    char minor_code;    /* Minor op-code of failed request */
    XID resourceid;      /* Window of failed request         */
} XErrorEvent;

XGetErrorText(display,code,buffer,length)/* returns a null terminated
                                             string  into buffer*/
    int code;  /* containing a verbal description of the    */
               /* error producing the code specified        */

As X is asynchronous errors may not be reported immediately they occur and this sometimes produces confusing effects when one is trying to debug a program. The following routine allows control of the synchronisation

int (*XSynchronize(display,onoff))()    /* returns previous state*/    
   int onoff;                              /* asynch = 0, else synch */