[comp.sys.apollo] The X Window System on Domain/OS: Questions and Answers part 2

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.