oj@apollo.HP.COM (Ellis Oliver Jones) (11/19/89)
This posting covers X Window System questions from programmers.
The previous posting covered user questions.
A disclaimer: keeping the Q&A log and answering the questions has been a
midnight project for myself and others. I take personal responsibility
for errors in this material, and I hope anyone spotting an error will
inform both me and comp.sys.apollo. Nothing in this posting should be
interpreted as the "official" position of HP.
Enjoy!
Ollie Jones.
Question: Does Xlib support anything like the external GPR bitmap file?
Answer: Not really. It supports an ASCII representation for single-plane
bitmaps. This ASCII representation is in a form that can be read/written
by Xlib (XReadBitmapFile/XWriteBitmapFile) or #included in a C program.
See /usr/X11/include/bitmaps/star for an example.
Q: How do I use Apollo event counts with X, rather than the Berkeley
select(2) call?
A: (thanks to Joe Bowbeer) On SR10.2, look at
/usr/X11/examples/x_and_gpr_input/x_and_gpr_input.c
The gist of it is this: (1) retrieve the event count for the socket used by the X
display connection:
#define necs 2 /* or whatever number of event counts you want */
#define ix 0 /* or whatever index you want for X waits */
#define igpr 1 /* or whatever... */
Display *display; /* X display structure */
ec2_$ptr_t ec2_ptr[necs]; /* arrays for ec2_$wait */
unsigned long ec2_val[necs];
status_$t status; /* status code for sys calls */
...
ios_$get_ec( (ios_$id_t)ConnectionNumber(display),
ios_$get_ec_key, &ec2_ptr[ix], &status);
ec2_val[ix] = ec2_$read(*ec2_ptr[ix]);
(2) initialize any other event counts you want in the event count arrays. For
example:
gpr_$get_ec(gpr_$input_ec, &ec2_ptr[igpr], &status);
ec2_val[igpr] = ec2_$read(*ec2_ptr[igpr]);
(3) in your main loop, use ec2_$wait to block, rather than XNextEvent or
gpr_$event_wait:
while (!quit) {
XFlush(display); /* flush X display connection before blocking */
which = ec2_$wait (ec2_ptr, (ec2_$val_list_t)ec2_val,
necs, &status);
switch (--which) { /* decrement for 0-based indices */
case igpr:
/* advance ec */
ec2_val[igpr] = ec2_$read(*ec2_ptr[igpr]) + 1;
do { /* flush gpr events. gpr calls refresh entry here */
gpr_$cond_event_wait(&event, &button, &position, &status);
if (event != gpr_$no_event)
/* process the gpr event */
} while (!quit && (event != gpr_$no_event));
break;
case ix:
/* advance ec */
ec2_val[ix] = ec2_$read(*ec2_ptr[ix]) + 1;
while (0 != XEventsQueued(display, QueuedAfterReading)) {
XNextEvent(display, &event);
/* process all queued X events */
}
break;
} /* end switch (--which) */
} /* end while (!quit) */
This uses plain-old event-count handling. You can use whatever event
counts you wish for this; you're not limited to GPR and X event counts.
Q: My application references include files that I can't seem to locate:
#include <Xr/keycode.h>
#include <Xw/Xw.h>
#include <Xw/XwP.h>
A: These include files have to do with HP toolkits. You can find up-to-
date copies of the Xw stuff via ftp on expo.lcs.mit.edu. The Xr stuff is from a
library called Xrlib, colloquially known as Xray. You might consider
switching to OSF/Motif.
Q: Is there a way to draw vertical text in x? I want to label the vertical
axis of a graph.
A: Short answer: No.
Long answer: There's an XV11R2 font called rot-s16 which has characters
oriented going down the page. If you image each character with a separate
Xlib call, each on its own baseline, you can label axes. Yuk, but functional.
Q: Is there any easy way of converting a font charater to an X bitmap?
A: This depends on what you mean by "X bitmap", and what you mean
by "easy." You can make an X bitmap file with the client named "bitmap,"
and digitize the character's bits. This is easy from a coding point of view
but quite hard work.
You can use xfd to display all the characters in a font in an on-screen
window.
You can make a one-plane Pixmap and draw your character into it. Use
XLoadQueryFont, then XTextExtents to find out the size of the character,
then create the Pixmap, then draw the character into it. You could use
XWriteBitmapFile to move the Pixmap into a bitmap file.
If you wrote the code to do all this, it might be nice if you added it to the
bitmap client.
Q: In our new user interface, while the application is off performing
some computation, it is not waiting for any X events. Therefore there
appears to be no easy way to present the user with some sort of <Interrupt>
or <Abort> button.
A: Yes, this is a real problem with X-based applications. There's
another reason why you might try to keep watching the event queue while
your application is doing computations: some of them take a long time and
the user might do things to incur exposure events while they're going on.
They'd like it better if the refreshes came through correctly. Not all events
you'll get are interrupts from the user.
Here are some wild ideas on how maybe to manage this:
(1) do nothing...probably unacceptable.
(2) modify the long-running computations to somehow look for events.
(3) Whenever you start one of these long-running computes, spawn off a
little separate user interface process which merely displays an <Interrupt>
button, and if the user pushes it, sends a SIGTERM or something to the
main application process.
(4) Establish a signal handler and condition the X connection socket to
generate a signal when any X event arrives. Code the signal handler to look
ahead in the queue and figure out whether it's received something
meaning abort, in which case longjmp somewhere to clean up.
(5) Use a lightweight thread, created via the task_$create call. Be careful in
this case as Xlib is not guaranteed reentrant.
(6) Separate the UI process and the application's process. This is probably
the most robust and elegant solution. It has upfront labor, but I suspect the
investment will pay off handsomely in such areas as flexibility of the UI.
Q: I get the message "XIO: Operation would block" from my X client
program whenever I try to connect to the X server.
A: You may be defining the variable errno in your program
somewhere. This variable is reserved for use by the C runtime library in
reporting exceptional conditions to callers. Xlib receives reports from the
runtime library code to read and write sockets using errno, and if your
program defines errno you may confuse Xlib.
The best way to obtain access to errno in your program is to use this:
#include <errno.h>
If you must declare errno explicitly, do so with the following line only:
extern int errno;
Q: I'm having trouble porting my Xt-based application to Apollo
workstations. It works fine on HP9000-300 series workstations and Sun 3
workstations, but I'm getting bad data back from subroutines which create
widgets on the Apollos.
A: Both the 9000-300 series workstations and the Suns use C compilers
based on PCC. Machine registers in these compilers are allocated such
that D0 is used both for intermediate storage in computations and for
returning function results. So, if you leave out the "return" statement at
the end of a function compiled by such a compiler, the caller can get lucky
and receive the result of the last computational expression in the function.
The Domain C compiler is far less likely to allocate registers this way. A
good way to find this kind of programming mistake is to run lint.
Q: I'm getting protocol errors from my X application after I use
XDestroyWindow to eliminate one of my windows.
A: If you have an event-accepting loop which responds to MotionNotify
hints by doing XQueryPointer, you can get into trouble if you destroy the
window, because there may be some pending motion events after the
window's gone. What you need to do is clean out the event queue of those
MotionNotify events right after issuing the XDestroyWindow request; this
code will do the trick:
XEvent foo;
XDestroyWindow(dpy, w);
XSync (dpy,0);
while (XCheckWindowEvent ( dpy,
~(SubstructureNotifyMask|StructureNotifyMask), &foo ));
The advantage of this code is that it will flush out input and Expose events,
and leave window structure events (like, maybe, DeleteNotify and
UnmapNotify) around for regular event processing to handle; thus other
code can get notified of window destruction in due course if it cares.
It's not as drastic as XSync ( dpy, 1); which blows away all waiting events
for all windows. Notice this is a problem on all X workstations, not just apollos.
Q: When trying to compile some code under sys5 I get the following errors:
cc my.c /usr/X11/lib/libX11.a /usr/X11/lib/libXt.a -o my
/usr/include/X11/Xos.h: 69: Can't find include file strings.h
/usr/include/X11/Xos.h: 80: Can't find include file sys/file.h
/usr/include/X11/Xos.h: 98: Can't find include file sys/time.h
Define the symbol SYSV when compiling, and Xlib's includes will work
properly. Use "-DSYSV" as follows:
cc my.c -DSYSV /usr/X11/lib/libX11.a /usr/X11/lib/libXt.a -o my
Q: When compiling an x program I get some undefined globals.
cc -o xapp xapp.o -L/usr/lib/X11 -lX11 -lXt -lXaw
undefined first referenced
symbol in file
XtDestroyGC /usr/lib/X11/libXaw.a
XtGetGC /usr/lib/X11/libXaw.a
ld warning: Output file xapp not executable
What is wrong? Is there a way to dump the libXt.a to find out what are the
globals defined? Like /com/bind -map ??
A: You are specifying the order of your libraries incorrectly. Try this:
cc -o xapp xapp.o -L/usr/lib/X11 -lXaw -lXt -lX11
You can use /bin/nm (the Unix namelist command) to find out what
symbols are defined in an object, archive, or shareable library:
/bin/nm /usr/X11/lib/libXt.a | grep GC
Q: Mouse motion events (after a button-down event) are not getting
reported until after the button-up event. Why are the motion events being
delayed?
A: You are probably running "xev" or some other program which
receives MotionNotify events from the server and printfs them to the
standard output. Also, you're probably running this program from a DM
pad. The problem is, the share-mode server acquires the GPR display lock
while buttons are being held down, because of an X requirement that an
active button grab be in effect while the button is held down.
Your program receives the events at the correct time, and sends the output
to the DM. The DM queues it up and doesn't output it until the user
releases the button. Try running your program from an xterm rather than
a DM pad.
Q: I am trying to compile an X application which includes an
"Atoms.h" header file. I can't find "Atoms.h".
A: Atoms.h is an XV11R2 Xt intrinsics file. At XV11R3 it was renamed
StringDefs.h, and Apollo supplies the XV11R3 intrinsics with SR10.2.
Q: I have an X application that works fine in mono but fails to draw
anything at all on a color node. I'm using the following code:
fg = BlackPixel( dpy, DefaultScreen( dpy ));
bg = WhitePixel( dpy, DefaultScreen( dpy ) );
GC = XCreateGC(dpy, w, 0, 0);
XSetFunction(dpy, GC, GXxor);
XSetForeground(dpy, GC, fg );
XSetBackground(dpy, GC, bg );
XSetPlaneMask( dpy, GC, AllPlanes );
A: You've got things set up wrong for exclusive-or drawing. Set the
plane mask to fg xor bg, set fg to all ones, and set bg to zero.
XSetFunction(dpy, GC, GXxor);
XSetForeground(dpy, GC, AllPlanes );
XSetBackground(dpy, GC, 0 );
XSetPlaneMask( dpy, GC, fg^bg );
Alternatively, set the plane mask to fg xor bg and use GXinvert instead of
GXxor:
XSetFunction(dpy, GC, GXinvert);
XSetForeground(dpy, GC, fg );
XSetBackground(dpy, GC, bg );
XSetPlaneMask( dpy, GC, fg^bg );
Notice that this applies to all X workstations, not just Apollos.
Q: Is the source-code for any of the example programs from
the O'Reilly documentation series available somewhere?
A: It's in /usr/X11/src/oreilly.tar unless you told "config" not to install it.
See /usr/X11/src/README for an explanation.
Thanks to Kee Hinckley Rod Owen, Joe Bowbeer, Glen Valante, Craig
Wolpert, John Brezak, Jim Glading, Mike Burati and Rob Stanzel for some
of these answers. I take responsibility for any errors.