dshr@SUN.COM (David Rosenthal) (11/04/87)
This message contains an abridged draft of a paper I've submitted for the next Usenix. It describes two versions of the ``Hello, World'' program for X.11, one implemented using Xlib, and the other using the toolkit. It argues very strongly that using the toolkit is the right thing to do. The Xlib version is alarmingly long, but everything there has been argued out, and is important. I would not normally "publish" a draft of a forthcoming paper like this, but the issue of the "Hello, World" program has a certain urgency. Please treat the following as a draft - a final version will be published in some form. To print the paper, unpack the shell archive, and do: troff -ms xhw.ms There are still some formatting glitches, but the result should be readable. The shell archive includes the text of both programs, and an Imakefile for them. David. #! /bin/sh # This is a shar archive. Extract with sh, not csh. ## Imakefile echo '=>' Imakefile cat > Imakefile << '4391!Funky!Stuff!' SRCS1 = xhw0.c SRCS2 = xhw1.c SRCS3 = xhw3.c SRCS4 = hw.c OBJS1 = xhw0.o OBJS2 = xhw1.o OBJS3 = xhw3.o OBJS4 = hw.o SingleProgramTarget(xhw0, $(OBJS1), $(XLIB), ) SingleProgramTarget(xhw1, $(OBJS2), $(XLIB), ) SingleProgramTarget(xhw3, $(OBJS3), $(XTOOLLIB) $(OLDXRMLIB) $(XLIB), ) SingleProgramTarget(hw, $(OBJS4),, ) 4391!Funky!Stuff! ## hw.c echo '=>' hw.c cat > hw.c << '4391!Funky!Stuff!' #include <stdio.h> main() { printf("Hello, World\n"); } 4391!Funky!Stuff! ## hw1.c echo '=>' hw1.c cat > hw1.c << '4391!Funky!Stuff!' #include <stdio.h> main() { (void) printf("Hello, World\n"); exit (0); } 4391!Funky!Stuff! ## xhw.ms echo '=>' xhw.ms cat > xhw.ms << '4391!Funky!Stuff!' .ds Hw ``Hello, World'' .de Ip .IP \(bu 3 .. .\" These macros should select a typewriter font if you have one. .de LS .DS L .ft L .ta .6i 1.2i 1.8i 2.4i 3i 3.6i 4.2i .eo .. .de LE .ec .ft P .DE .. .TL A Simple X.11 Client Program .sp or .sp How hard can it really be to write \*(Hw? .sp DRAFT 22\s-2\und\d\s0 October 1987 .AU David S. H. Rosenthal .AI Sun Microsystems .AB .LP The \*(Hw program has achieved the status of a koan in the U\s-2NIX\s0 community. Various versions of this koan for Version 11 of the X Window System are examined, as a guide to writing correct programs, and as an illustration of the importance of the X.11 toolkit. .AE .QP `There, fourth graders discuss whether the machines prefer running simpler programs (``It's easier for them,'' ``They hardly have to do any work.'') or more complicated ones (``They feel proud,'' ``It's like they are showing what they can do.'').' .DS C Sherry Turkle \fIThe Second Self\fP. .DE .sp 2 .DS C Copyright \(co 1987 by Sun Microsystems, Inc.\s-2\u1\d\s0 .DE .FS 1. Permission to use, copy, modify and distribute this document for any purpose and without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies, and that the name of Sun Microsystems, Inc. not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. Sun Microsystems, Inc. makes no representations about the suitability of the software described herein for any purpose. It is provided "as is" without express or implied warranty. .FE .sp 2 .NH Introduction .LP The \*(Hw program has achieved the status of a koan in the U\s-2NIX\u2\d\s0 .FS 2 U\s-2NIX\s0 is a Registered Trademark of AT&T. .FE community. The spare elegance of: .LS .so hw.c .LE .LP has been much admired, and contrasted with the baroque complexity of other system's attempts to solve the problem.\s-2\u3\d\s0 .FS 3 Of course, it is important to note that this implementation has bugs. A more correct, ANSI C version is shown in the appendix. .FE .LP Various versions of the \*(Hw koan for Version 11 of the X Window System\s-2\u4\d\s0 .FS 4 The X Window System is a Trademark of the Massachusetts Institute of Technology. .FE are examined. They provide a guide to writing correct programs for X.11, insight into the complexity of the issues they have to deal with, and an illustration of the importance of the X.11 toolkit. .NH Specification .LP The \*(Hw problem needs to be restated slightly for the world of window systems. The program needs to: .Ip Create a window of an appropriate size, and position it on the screen if required. .Ip Paint the string \*(Hw in a suitable font, centered in the window. .Ip Paint the string in a color which will contrast with the window background \- it is not acceptable to paint an invisible string. .Ip Deal with its window being exposed \- repainting the window if required. .Ip Deal with its window being resized \- re-centering the text. .Ip Deal with its window being closed into an icon, and re-opened, providing suitable identification of the icon. .LP Note that this specification is much more complex than the canonical \*(Hw program, so that it is likely that the resulting programs will be significantly more complex. .NH Vanilla X.11 .LP The first \*(Hw example uses only the facilities of the basic X.11 library. .NH 2 Program Outline .Ip Open a connection to the X server. Exit gracefully if you cannot. .Ip Open the font to be used, and obtain the font data to allow string widths and heights to be calculated. .Ip Select pixel values for the window border, the window background, and the foreground that will be used to paint the characters. .Ip Compute the size and location of the window based on the text string and the font data, and set up the size hints structure. .Ip Create the window. .Ip Set up the standard properties for use by the window manager. .Ip Create a Graphics Context for use when painting the string. .Ip Select the types of input events that we are interested in receiving. .Ip Map the window to make it visible. .Ip Loop forever: .RS .Ip Obtain the next event. .Ip If the event is the last event of a group of Expose events (that is, it has \fBcount\ ==\ 0\fP), repaint the window by: .RS .Ip Discovering the current size of the window. .Ip Computing the position for the start of the string that will cause it to appear centered in the current window. .Ip Clearing the window to its background color. .Ip Drawing the string. .RE .RE .NH 2 Program Text .LP .nr PS -4 .nr VS -6 .LS .so xhw0.c .LE .nr PS +4 .nr VS +6 .NH 2 Does it meet the specification? .Ip It computes the size of the window from the string and the font, and positions it at the center of the screen. .Ip It paints the string in the color \fBWhitePixel(\|)\fP on a \fBBlackPixel(\|)\fP background. It ensures that the appropriate colormap will be used for the window, so that these colors (which may not actually be White and Black) will be distinguishable. .Ip Every time it gets the last of a group of Expose events, it enquires the size of the window, and paints the string centered in this space. In particular, it will get an Expose event initially as a consequence of its mapping the window, and will thus paint the window for the first time. .Ip The same mechanism copes with part or all of the window being exposed. The program will re-paint the entire window when any part is exposed; in this case the effort of only repainting the exposed parts is excessive. .Ip The fact that the string is re-centered every time the window is painted means that the program deals with re-sizing correctly. Subject to the caveats below, when the window is resized, an Expose event will be generated, and the window will be re-painted. .Ip The standard properties that the program sets include a specification of a string that a window manager can display in the icon. The programs sets this to be the string it is displaying, so it copes with being iconified. When it is opened, an Expose event will be generated, and the window will be re-painted. .NH 2 Design Issues .LP Although this implementation of \*(Hw is alarmingly long, it is structurally simple. Nevertheless, there are many detailed design issues that arise when writing it. This section covers them, in no particular order. .NH 3 Repaint Strategy. .LP Every X.11 application has the responsibility for re-painting its image whenever the server requests it to. It is possible to refresh only the parts requested, or to refresh the entire window. The \*(Hw image is simple enough that refreshing the entire image is a sensible approach. .LP Exposing part or all the window results in one or more Expose events. Each carries, in the \fBcount\fP field, the number of events in the same group that follow it. After receiving the last of each group, identified by a zero \fBcount\fP, the window is re-painted. .LP Re-painting on \fIevery\fP Expose event would result in unnecessary multiple repaints. For example, consider a \*(Hw that appears for the first time with one corner overlain by another window. The newly exposed area consists of two rectangles, so there will be two Expose events in the initial group. .LP We actually take even more rigorous measures to avoid multiple repaints. Every time we decide to repaint the window, we scan the event queue and remove all Expose events that have arrived at the client, but which have yet to arrive at the head of the queue. .NH 3 Resize Strategy .LP The first time the window is painted, it seems as if enquiring the size of the window is unnecessary. We have, after all, just created the window and told it what size to be. But X.11 does not allow us to assume that the window will actually get created at the requested size; we have to be prepared for a window manager to have intervened and overridden our choice of size. So it is necessary to enquire the window size on the initial Expose event. .LP When the window is resized, the client needs to re-compute the centering of the text. The implementation does this on the last of every group of Expose events. This raises two questions .Ip Does every resize of the window result in at least one Expose event? .IP Consider a window, not obscured by others, that is resized to make it smaller. The X.11 server actually has enough pixels to fill the new window size; there is no need to generate an Expose event to cause pixels to be repainted. This is the simplest example of what the X.11 specification calls ``Bit Gravity''. Clients may reduce the number of Expose events they receive by specifying an appropriate Bit Gravity. Even if the window is made larger, the Bit Gravity can tell the server how to re-locate the old pixels in the new window to avoid Expose events on parts of the window whose contents are not supposed to change. .IP By default, X.11 sets the Bit Gravity of windows to \fBForgetGravity\fP. This ensures that the gravity mechanism is disabled, Expose events occur on all resizings of the window, and the \*(Hw program operates correctly if the whole issue of Bit Gravity is ignored. In this default case, the answer to the question is ``Yes, every resize results in at least one Expose event''. .IP But we can exploit Bit Gravity to avoid unnecessary repaints by setting it to \fBCenterGravity\fP. This will preserve the centering of the text if the window is resized smaller without involving the client program. In this case, the answer to the question is ``No, not every resize results in an Expose event''. But in the cases where no Expose event occurs, the window will still be correct. .Ip Can we avoid the overhead of enquiring the window size on every re-paint? .IP As we have seen, Expose events have no direct relation to window re-sizing. In general, X.11 clients should listen for both: .RS .Ip Expose events, which tell them to re-paint some part of the window. .Ip ConfigureNotify events, which tell them that the window has been changed in some way which requires that the image be re-computed. .RE .IP In principle, \*(Hw should only re-compute the centering of the text when it gets a ConfigureNotify event. But the overhead of the extra round-trip to the server to enquire about the size of the window on every Expose event is not critical for this application, and the code in this case is much simpler. .LP There is an extra piece of inelegance in this implementation. The correct way of discovering the size of the window, which is all we need to recompute the centering of the text, is to use \fBXGetGeometry(\|)\fP. We use \fBXGetWindowAttributes(\|)\fP instead; it returns all sorts of other information that we don't need, but we happen to have an \fBXWindowAttributes\fP structure handy to put the results in. .NH 3 Communicating with the Window Manager .LP Every X application must use some properties on its window to communicate with the window manager. .Ip The WM hints, containing information for the window manager about the input and icon behaviour of the window. In the case of \*(Hw, this information is known at compile time and can be intialized statically. .Ip The size hints, containing information about the size and position of the window. These cannot be initialized statically since they depend on the font properties, and are only known at run-time. .Ip Other properties, including \fBWM_NAME\fP, \fBWM_ICON_NAME\fP, and \fBWM_COMMAND\fP, which are used to communicate strings such as the name of the program running behind the window. .Ip The colormap field of the window is not a property, but it may also be used to communicate with the window manager. The conventions about this have yet to be fully specified, and the topic is covered in the next section. .NH 3 Colormaps and Pixel Values. .LP To ensure \*(Hw works on both monochrome & color displays, we use the colors Black and White\s-2\u5\d\s0. .FS 5 These colors may not actually be black and white, but they are guaranteed to contrast with each other. .FE To paint in a color using X.11, you need to know the pixel value corresponding to it; the pixel value is the number you write into the pixel to cause that color to show on the screen. .LP Although X.11 specifies that Graphics Contexts are by default created using 0 and 1 for the background and foreground pixel values, an application cannot predict the colors that these pixel values will resolve to. It cannot even predict that these two colors will be different, so every application must explicitly set the pixel values it will use. .LP Pixel values are determined relative to a Colormap; X.11 supports an arbitrary number of colormaps, with one or more being installed in the hardware at any one time. X.11 supports these colormaps even on monochrome displays. There is a default colormap, which applications with modest color requirements are urged to use, and \*(Hw is as modest as you could wish. In fact, the colors Black and White have pre-defined pixel values in the default colormap, and we can use these directly. .LP However, using the pre-defined values means that \*(Hw becomes dependent on having the default colormap installed. Unless it is, they may not be distinguishable. Unfortunately, when a window is created using \fBXCreateSimpleWindow(\|)\fP the colormap is inherited from the parent (in our case, the root window for the default screen), and it is possible that some client may have set the colormap of the root to something other than the default colormap. So, for now, we have to set the colormap field of the window explicitly to be the default colormap, although it is anticipated that when the conventions for window management are finally determined this code will be unnecessary. .LP Simply setting the colormap field of the window does not ensure that the correct colormap will actually be installed. The whole question of whether, and when, clients should install their colormaps is open to debate at present. There are two basic positions: .Ip Clients should explicitly install their own colormap when appropriate, for example when they obtain the input focus. .IP This has two disadvantages, in that it makes every client much more complicated (it means, for example, that \*(Hw has to worry about the input focus!), and that it means that every client will be doing the wrong thing eventually, when window managers start doing the right thing (whatever that is!). It does, however, mean that clients will work right now. .Ip Clients should never install their own colormaps, and should assume that some combination of the internals of the server, and the window manager, will do it for them. .IP This has the disadvantage that it will not work at present, since existing window managers don't appear to do anything with colormaps. .LP Strictly speaking, therfore, \*(Hw should deal with installing colormaps, since the policy has yet to be determined. But it would make the code so complex as to be out of the question for a paper such as this. .NH 3 Error Handling .LP It appears that this \*(Hw implementation follows the canonical \*(Hw implementation in the great U\s-2NIX\s0 tradition of optimism, by ignoring the possibility of errors. Not so, the question of error handling has been fully considered: .Ip On the \fBXOpenDisplay(\|)\fP call, we check for the error return, and exit gracefully. .Ip When opening the font, we cannot be sure that the server will map that name into a font. So we check the error return, and exit gracefully, if the server objects to the name. .Ip For all other errors, we depend on the default error handling mechanism. When an X.11 client gets an Error event from the server, the library code invokes an error handler. The client is free to override the default one, which prints an informative message and exits, but its behaviour is fine for \*(Hw. .LP Of course, one might ask why we need to explicitly check for errors on opening the font. Surely, the default error handler does what we want? It is an (alas, undocumented) feature of Xlib that not all errors cause the error handler to be invoked. Some errors, such as failure to open a font, are regarded as failure status returns and are signalled by Status return values \- in general any routine that returns Status will need its return tested, because it will have bypassed the error handling mechanism. .NH 3 Finding a Server. .LP The particular server to use is identified by the \fB$DISPLAY\fP environment variable\s-2\u6\d\s0, .FS 6 Non-U\s-2NIX\s0 systems will use some other technique. .FE so it does not need to be specified explicitly. It is a convention among X.11 clients that a command-line argument containing a colon is a specification of the server to use, but this version of \*(Hw does not support the convention (or any other command-line arguments). .NH 3 Looping for events. .LP It is natural to assume that you can write the event wait loop: .LS while (XNextEvent(dpy, &event) { .\|.\|.\|.\|.\|. } .LE .LP but this is not the case. \fBXNextEvent(\|)\fP is defined to be void; it only ever returns when there is an event to return, and errors are handled through the error handling mechanism, rather than being indicated by a return value. So it is necessary to write the event loop: .LS while (1) { XNextEvent(dpy, &event); .\|.\|.\|.\|.\|. } .LE .NH The Toolkit .LP Examining the preceding example, anyone would admit that the basic X.11 library fails the \*(Hw test. Even the simplest \*(Hw client takes 40 executable statements, and 25 calls through the X.11 library interface. .LP All is not lost, however. It was never intended that normal applications programmers would use the basic X.11 library interface. An analogy is that very few U\s-2NIX\s0 programmers use the raw system call interface, they almost all use the higher-level ``Standard I/O Library'' interface. The canonical \*(Hw program is an example. .LP The X.11 distribution includes a user interface toolkit, intended to provide a more congenial environment for applications development in exactly the same way that \fIstdio\fP does for vanilla U\s-2NIX\s0. Using the toolkit, the following example shows that X.11 can pass the \*(Hw test with ease. .NH 2 Program Outline .LP The outline of the program is: .Ip Create the top level Widget that represents the toolkit's view of the (top-level) window. .Ip Create a Label Widget to display the string, over-riding the defaults database to set the Label's value to the string to display. .Ip Tell the top level Widget to display the label, by adding it to the top level Widget's managed list. .Ip Realize the top level Widget (and therefore its sub-Widgets). This process creates an X.11 window for each Widget, setting its attributes from the data in the Widget. .Ip Loop forever, processing the events that appear. .NH 2 Program Text .nr PS -4 .nr VS -6 .LS .so xhw3.c .LE .nr PS +4 .nr VS +6 .NH 2 Does it meet the specification? .LP This implementation of \*(Hw fulfills the specification: .Ip The window is sized as a result of the geometry negotiation between the top level Widget and its sub-Widgets (in this case the label), so that by default the window is sized to fit the text. .Ip The default attributes for the Label Widget specifiy that the text is centered, and the default mechanism supplies a suitable font. .Ip In the same way, the default mechanism supplies background and foreground colors for the Widget. .Ip The toolkit manages all Expose events, routing them to appropriate Widgets. Thus, the program behaves correctly for exposure. .Ip The Label Widget recomputes the centering of the text whenever it is being painted, so that resizing is handled correctly. .Ip The toolkit handles communicating with the window manager about icon properties, so that iconification is handled correctly. .NH 2 Design Issues .LP Note that this implementation isn't merely much shorter than the earlier examples. It has an additional useful feature, in that any or all the values from the default database used by the program can be overridden by command line arguments. \fBXtInitialize(\|)\fP parses the command line and merges any specifiers it finds there with the defaults database. .LP The toolkit also provides peace of mind by organizing the error handling correctly. Although the documentation of error handling in the toolkit manual is sparse, experiments seem to show that the implementation is satisfactory, providing intelligible messages and sensible behaviour. .NH Conclusions .LP These examples demonstrate that programming applications using only the basic X library interface is even more difficult and unrewarding than programming U\s-2NIX\s0 applications using only the system call interface. .LP Just as anyone considering developing U\s-2NIX\s0 applications should use \fIstdio\fP, anyone considering developing X.11 applications should use the toolkit. In the case of \*(Hw, a client that took 40 executable statements to program using the basic X.11 library took 5 statements to program using the toolkit. .SH Acknowledgements .LP Richard Johnson <raj@limbo.UCI.EDU> posted the first attempt at a \*(Hw program for X.11 to the \fIxpert\fP mailing list. This, and Ellis Cohen's praiseworthy attempts to write up the conventions needed for communicating between applications and window managers, inspired me to try to write the \*(Hw program right. .LP Jim Gettys, Bob Scheifler, & Mark Opperman all identified bugs and suggested fixes in the Vanilla version. The toolkit version is derived from \fIlib/Xtk/clients/xlabel\fP. .SH Appendix: ANSI C Hello World .LP .LS .so hw1.c .LE .Ip ANSI C specifies that printf() returns the number of characters printed. .Ip It is necessary to exit() or return() a value from main(). 4391!Funky!Stuff! ## xhw0.c echo '=>' xhw0.c cat > xhw0.c << '4391!Funky!Stuff!' #include <stdio.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #define STRING "Hello, world" #define BORDER 1 #define FONT "vrb-25" /* * This structure forms the WM_HINTS property of the window, * letting the window manager know how to handle this window. * See Section 9.1 of the Xlib manual. */ XWMHints xwmh = { (InputHint|StateHint), /* flags */ False, /* input */ NormalState, /* initial_state */ 0, /* icon pixmap */ 0, /* icon window */ 0, 0, /* icon location */ 0, /* icon mask */ 0, /* Window group */ }; main(argc,argv) int argc; char **argv; { Display *dpy; /* X server connection */ Window win; /* Window ID */ GC gc; /* GC to draw with */ XFontStruct *fontstruct; /* Font descriptor */ unsigned long fth, pad; /* Font size parameters */ unsigned long fg, bg, bd; /* Pixel values */ unsigned long bw; /* Border width */ XGCValues gcv; /* Struct for creating GC */ XEvent event; /* Event received */ XSizeHints xsh; /* Size hints for window manager */ char *geomSpec; /* Window geometry string */ XWindowAttributes xwa; /* Temporary Window Attribute struct */ /* * Open the display using the $DISPLAY environment variable to locate * the X server. See Section 2.1. */ if ((dpy = XOpenDisplay(NULL)) == NULL) { fprintf(stderr, "%s: can't open %s\n", argv[0], XDisplayName(NULL)); exit(1); } /* * Load the font to use. See Sections 10.2 & 6.5.1 */ if ((fontstruct = XLoadQueryFont(dpy, FONT)) == NULL) { fprintf(stderr, "%s: display %s doesn't know font %s\n", argv[0], DisplayString(dpy), FONT); exit(1); } fth = fontstruct->max_bounds.ascent + fontstruct->max_bounds.descent; /* * Select colors for the border, the window background, and the * foreground. */ bd = WhitePixel(dpy, DefaultScreen(dpy)); bg = BlackPixel(dpy, DefaultScreen(dpy)); fg = WhitePixel(dpy, DefaultScreen(dpy)); /* * Set the border width of the window, and the gap between the text * and the edge of the window, "pad". */ pad = BORDER; bw = 1; /* * Deal with providing the window with an initial position & size. * Fill out the XSizeHints struct to inform the window manager. See * Sections 9.1.6 & 10.3. */ xsh.flags = (PPosition | PSize); xsh.height = fth + pad * 2; xsh.width = XTextWidth(fontstruct, STRING, strlen(STRING)) + pad * 2; xsh.x = (DisplayWidth(dpy, DefaultScreen(dpy)) - xsh.width) / 2; xsh.y = (DisplayHeight(dpy, DefaultScreen(dpy)) - xsh.height) / 2; /* * Create the Window with the information in the XSizeHints, the * border width, and the border & background pixels. See Section 3.3. */ win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), xsh.x, xsh.y, xsh.width, xsh.height, bw, bd, bg); /* * Set the standard properties for the window managers. See Section * 9.1. */ XSetStandardProperties(dpy, win, STRING, STRING, None, argv, argc, &xsh); XSetWMHints(dpy, win, &xwmh); /* * Ensure that the window's colormap field points to the default * colormap, so that the window manager knows the correct colormap to * use for the window. See Section 3.2.9. Also, set the window's Bit * Gravity to reduce Expose events. */ xwa.colormap = DefaultColormap(dpy, DefaultScreen(dpy)); xwa.bit_gravity = CenterGravity; XChangeWindowAttributes(dpy, win, (CWColormap | CWBitGravity), &xwa); /* * Create the GC for writing the text. See Section 5.3. */ gcv.font = fontstruct->fid; gcv.foreground = fg; gcv.background = bg; gc = XCreateGC(dpy, win, (GCFont | GCForeground | GCBackground), &gcv); /* * Specify the event types we're interested in - only Exposures. See * Sections 8.5 & 8.4.5.1 */ XSelectInput(dpy, win, ExposureMask); /* * Map the window to make it visible. See Section 3.5. */ XMapWindow(dpy, win); /* * Loop forever, examining each event. */ while (1) { /* * Get the next event */ XNextEvent(dpy, &event); /* * On the last of each group of Expose events, repaint the entire * window. See Section 8.4.5.1. */ if (event.type == Expose && event.xexpose.count == 0) { int x, y; /* * Remove any other pending Expose events from the queue to * avoid multiple repaints. See Section 8.7. */ while (XCheckTypedEvent(dpy, Expose, &event)); /* * Find out how big the window is now, so that we can center * the text in it. */ if (XGetWindowAttributes(dpy, win, &xwa) == 0) break; x = (xwa.width - XTextWidth(fontstruct, STRING, strlen(STRING))) / 2; y = (xwa.height + fontstruct->max_bounds.ascent - fontstruct->max_bounds.descent) / 2; /* * Fill the window with the background color, and then paint * the centered string. */ XClearWindow(dpy, win); XDrawString(dpy, win, gc, x, y, STRING, strlen(STRING)); } } exit(1); } 4391!Funky!Stuff! ## xhw3.c echo '=>' xhw3.c cat > xhw3.c << '4391!Funky!Stuff!' #include <stdio.h> #include <X11/Xlib.h> #include <X11/Intrinsic.h> #include <X11/Atoms.h> #include <X11/Label.h> #define STRING "Hello, World" Arg wargs[] = { XtNlabel, (XtArgVal) STRING, }; main(argc, argv) int argc; char **argv; { Widget toplevel, label; /* * Create the Widget that represents the window. * See Section 14 of the Toolkit manual. */ toplevel = XtInitialize(argv[0], "XLabel", NULL, 0, &argc, argv); /* * Create a Widget to display the string, using wargs to set * the string as its value. See Section 9.1. */ label = XtCreateWidget(argv[0], labelWidgetClass, toplevel, wargs, XtNumber(wargs)); /* * Tell the toplevel widget to display the label. See Section 13.5.2. */ XtManageChild(label); /* * Create the windows, and set their attributes according * to the Widget data. See Section 9.2. */ XtRealizeWidget(toplevel); /* * Now process the events. See Section 16.6.2. */ XtMainLoop(); } 4391!Funky!Stuff!
paulsh@shark.gwd.tek.COM (11/18/87)
David, Thanks for the Hello World for X.11 programs. They have proved to be useful templates. I am submiting the following corrections that I discovered when using the programs. I'll post them to xpert to avoid duplicate bug reports. 1) The version of make I am using failed due to the tabs at the beginning of the macro definition lines. Thus I removed the tabs on those lines in the Imakefile. 2) The Xlib routine XChangeWindowAttributes() requires a pointer to a XSetWindowAttributes structure and not a pointer to a XWindowAttributes structure. Thus I declared a new variable XSetWindowAttributes xswa; and used it in the assignments and the call to XChangeWindowAttributes(). Patches for these two fixes are given below. Thanks again for the programs. Paul Shearer M.S. 61-277 Tektronix, Inc. P.O. Box 1000 Wilsonville, OR 97070-1000 W (503) 685-2137 tektronix!shark!paulsh -------------------- *** /tmp/,RCSt1025182 Wed Nov 18 10:09:33 1987 --- Imakefile Wed Nov 18 10:09:51 1987 *************** *** 1,11 ! SRCS1 = xhw0.c ! SRCS2 = xhw1.c ! SRCS3 = xhw3.c ! SRCS4 = hw.c ! OBJS1 = xhw0.o ! OBJS2 = xhw1.o ! OBJS3 = xhw3.o ! OBJS4 = hw.o SingleProgramTarget(xhw0, $(OBJS1), $(XLIB), ) --- 1,11 ----- ! SRCS1 = xhw0.c ! SRCS2 = xhw1.c ! SRCS3 = xhw3.c ! SRCS4 = hw.c ! OBJS1 = xhw0.o ! OBJS2 = xhw1.o ! OBJS3 = xhw3.o ! OBJS4 = hw.o SingleProgramTarget(xhw0, $(OBJS1), $(XLIB), ) *** /tmp/,RCSt1010641 Tue Nov 17 18:26:40 1987 --- xhw0.c Tue Nov 17 18:26:14 1987 *************** *** 37,42 XEvent event; /* Event received */ XSizeHints xsh; /* Size hints for window manager */ char *geomSpec; /* Window geometry string */ XWindowAttributes xwa; /* Temporary Window Attribute struct */ /* --- 37,43 ----- XEvent event; /* Event received */ XSizeHints xsh; /* Size hints for window manager */ char *geomSpec; /* Window geometry string */ + XSetWindowAttributes xswa; /* Set Window Attribute struct */ XWindowAttributes xwa; /* Temporary Window Attribute struct */ /* *************** *** 105,113 * use for the window. See Section 3.2.9. Also, set the window's Bit * Gravity to reduce Expose events. */ ! xwa.colormap = DefaultColormap(dpy, DefaultScreen(dpy)); ! xwa.bit_gravity = CenterGravity; ! XChangeWindowAttributes(dpy, win, (CWColormap | CWBitGravity), &xwa); /* * Create the GC for writing the text. See Section 5.3. --- 106,114 ----- * use for the window. See Section 3.2.9. Also, set the window's Bit * Gravity to reduce Expose events. */ ! xswa.colormap = DefaultColormap(dpy, DefaultScreen(dpy)); ! xswa.bit_gravity = CenterGravity; ! XChangeWindowAttributes(dpy, win, (CWColormap | CWBitGravity), &xswa); /* * Create the GC for writing the text. See Section 5.3.