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 */