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.