In this section I present a simple nano-X application. This application is the classic "hello world" in nano-X style. When you run the application you will see a single white window with the text "Hello World". If you run the application with nanowm the application's window will have a title bar, and a resizable border.
Copy the source shown below into a file named "hello.c". Compile the application with the following command.
$ gcc hello.c -o hello -lnano-X |
Example 1-1. hello.c
#include <stdio.h> #define MWINCLUDECOLORS #include "microwin/nano-X.h" GR_WINDOW_ID wid; GR_GC_ID gc; void event_handler (GR_EVENT *event); int main (void) { if (GrOpen() < 0) { fprintf (stderr, "GrOpen failed"); exit (1); } gc = GrNewGC(); GrSetGCUseBackground (gc, GR_FALSE); GrSetGCForeground (gc, RED); wid = GrNewWindowEx (GR_WM_PROPS_APPFRAME | GR_WM_PROPS_CAPTION | GR_WM_PROPS_CLOSEBOX, "Hello Window", GR_ROOT_WINDOW_ID, 50, 50, 200, 100, WHITE); GrSelectEvents (wid, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_CLOSE_REQ); GrMapWindow (wid); GrMainLoop (event_handler); } void event_handler (GR_EVENT *event) { switch (event->type) { case GR_EVENT_TYPE_EXPOSURE: GrText (wid, gc, 50, 50, "Hello World", -1, GR_TFASCII); break; case GR_EVENT_TYPE_CLOSE_REQ: GrClose(); exit (0); } } |
The header file "microwin/nano-X" defines the Microwindows and nano-X data structures, variables and functions. This file will be included in all source files that make nano-X API calls.
If we start at the top with the include files you will first notice the define for MWINCLUDECOLORS. This definition enables the definition of common system colors. The following color names can be used if MWINCLUDECOLORS is defined before the nano-X header files.
A single function call, GrOpen(), will open and initialize the nano-X library. The function sets up the screen, keyboard and mouse device interfaces. This must be the first nano-X function that your application calls.
Nano-X uses objects called graphics contexts to describe drawing attributes. Among other things a graphics context (GC) will describe the colors to use when drawing graphical objects using nano-X.
Your application may allocate as many graphics contexts as you wish. Each drawing function call takes a GC as a parameter. For example if you wanted to draw red and blue text on a white background you might create one GC. You could set the foreground color to red and draw the red text. Then set the foreground color to blue and draw the blue text. Another approach is to create two GCs, one with a red foreground and the other with a blue foreground. With two GCs you would use the first GC for drawing red text and the second GC for drawing blue text.
In the "hello world" example I create one GC using the GrNewGC() function. Then I configure the GC so that it does not use a background color and I set the foreground color to red. I save the ID of the GC for use later when I start drawing onto the application window.
Now you're going to need a window to draw onto. The next section of the example creates a main window for the application. The GrNewWindowEx() function creates our "hello world" application's main window. GrNewWindowEx() is the preferred method to create windows. Another function GrNewWindow() has been depreciated since it can not specify window decoration options to a window manager.
In this example we have a single main window with a title bar. The title bar caption reads "Hello Window".
In nano-X you must select the types of events that you want a window to receive. After you create the window, you must make a call to the GrSelectEvents() function to choose the events that the window will receive. In our example we choose to receive exposure events and close request events.
By selecting exposure events you will know when the window needs to be redrawn. By selecting close request events, you will know when the window is closed.
To make the window visible your application must "map" the window. You will call the function GrMapWindow() to make the window visible.
After creating the main window, selecting events and mapping the window, the application can enter it's main event dispatch loop. The nano-X library provides several ways to implement the application's event dispatch loop. The easiest of these methods is the GrMainLoop() function. This function takes as a parameter, a pointer to your application's event handler. The event handler function will be invoked each time that the nano-X event queue receives a selected event.
In the example the function event_handler() serves as the event handler. Within this function is a switch on the event type. The two events that we select in the example are the exposure event and the close request event.
Exposure events are nano-X's means of asking the application to redraw the contents of a window. Your application must redraw the window contents each time it gets an exposure event. You can not draw the window once and then forget about what's in there.
You will receive an exposure event after the window is mapped for the first time. You will also receive exposure events when the window is re-exposed. For example, let's imagine another window within your application or another application covers your window. When that window is moved exposing a portion, or all of, your window, nano-X will send your application an exposure event.
In our example we handle the exposure event by drawing the text "hello world" onto the window. Notice that when we call the function GrText() we specify a window ID and a graphics context ID. These are the IDs that we received earlier when we created the window and the GC.
When you close the application window nano-X sends a close request event. The hello world application calls GrClose() to close the connection to the nano-X server. Then we exit the application.
Run the "hello world" application with the following command. You will see a window appear as shown below.
$ nano-X& sleep 1; nanowm& sleep 1; ./hello& |
This simple example program shows the structure of most, even much more complicated, nano-X applications. You will almost always connect to server, create windows and GCs, select events, map the windows and then process events.