This is G o o g l e's cache of http://nestroy.wi-inf.uni-essen.de:8080/Lv/gui/cg252/tutorials/tute31.html as retrieved on 4 Nov 2004 08:00:00 GMT.
G o o g l e's cache is the snapshot that we took of the page as we crawled the web.
The page may have changed since that time. Click here for the current page without highlighting.
This cached page may reference images which are no longer available. Click here for the cached text only.
To link to or bookmark this page, use the following url: http://www.google.com/search?q=cache:g1wYquv3MKkJ:nestroy.wi-inf.uni-essen.de:8080/Lv/gui/cg252/tutorials/tute31.html+imake+tutorial&hl=en&ct=clnk&cd=18&client=opera


Google is neither affiliated with the authors of this page nor responsible for its content.
These search terms have been highlighted: imake tutorial 

X-Google-Crawl-Date: Sat, 27 Nov 2004 04:56:35 GMT CG252-502 Tutorial 3
     DATE:                   CG252/502              Tutorial: 3


                        Xlib Programs

  

We will now start to look at a low level Xlib program. This is the "assembler" level of programming for X Windows. We will not spend much time on it but you need to know about this level

  to understand the X structure and levels

to realize the resources such as Window ids and Graphics Contexts used
just in case

(1) Get a copy of the contents of the tute3a directory in the graphics area. How?

    mkdir ~/tute3a; cd ~/tute3a 

cp $g/tute3a/*.c $g/tute3a/*.h $g/tute3a/Imakefile .
(Make sure you DO include the dot at the end).

(People not at Curtin may like to use to retrieve the files.)

(2) Imake is a tool for generating Makefiles1 for large software distributions. (See footnote 1) Imake and xmkmf use the C preprocessor on macro-makefiles (called Imakefiles) to generate Makefiles. They use a predefined template file for default values and macros. The imake and xmkmf programs are part of, and used by the X Windows System software distribution. Makefiles by themselves have some limitations for large software distributions, distributed over multiple directories, viz.

A single makefile doesn't handle multiple directories well, which means that each directory needs a makefile. At that point, to change a default value, for example the directory where the binaries are to be installed, you have to change all the makefiles.

Typically, makefiles are used to achieve a limited set of actions, like create a binary from a set of object files, or generate a library from some object files, etc. These can be encapsulated in rules that are slightly more complex that the ones make supports (which are only suffix based)

A production makefile which supports all the actions necessary for a development environment, can get fairly long --- typically, you want a clean target, an install target, a depend target, and an all target.

For a system that is ported to many different systems, there are bound to be differences in the requirements of the systems, that cannot be dealt with solely at the C source level. Vanilla make allows no facilities for changes like this, and you end up having multiple makefiles, with suffixes to indicate the type of system being used.

Cat the Imakefile. This is the template which we will use:

 LOCAL_LIBRARIES = $(XLIB)

SRCS = init.c main.c open_window.c
OBJS = init.o main.o open_window.o
ComplexProgramTarget(tute3a)

This tells us what the source files are, what the object files are, what the linking library is and finally invokes a macro to build the executable from the sources, objects and libraries. The macro names for the files are not random but must be as shown because the macro ComplexProgramTarget uses them.
Try to run make. It doesn't work as there isn't a Makefile. We have to create the Makefile from the Imakefile. We can do this with the xmkmf program - xmake makefile.

(1) Try

    xmkmf; more Makefile 


- the Makefile was created by xmkmf. Take a few minutes to see how complex it is.

(2) Rerun xmkmf with the -a (all) flag. The output should be roughly:

 mv Makefile Makefile.bak

imake -DUseInstalled -I/usr/lib/X11/config
make Makefiles
make includes
make depend
makedepend -s "# DO NOT DELETE" -- -I/usr/include -DSYSV -DMALLOC_0_RETURNS_NULL -DFUNCPROTO -DNARROWPROTO -- init.c main.c open_window.c

That is, save the old Makefile and then run imake to build the new Makefile given the specified X environment. The -a switch now runs "make Makefiles" so that, in a big project with many sub-directories, all sub-directory Makefiles are also created. Next, the make include will ensure that all include files that are needed are installed in their correct places. Lastly, and very importantly for the Makefile, make depend will examine each source program to determine what source program depends upon what include file - all the work is done for you!!!
We will now do a make. Use the commands given below. Students should get used to this process as they will be doing it nearly every tute.

    xmkmf -a 

make

Take note of the commands being issued by the Makefile. In particular notice the definitions and include directories.

     -lX11_s   : shared (_s) X11 Lib routines.

This library may have a different name on different platforms

The compiling and linking will take a while especially if there are many people on the machines. Therefore the quicker you are at starting commands, the faster you will finish due to network overheads, etc.
     

Students at Curtin.


Please note that programs compiled on the Indies will not work on the old machines but those compiled on the old will work on the new. The new format, ELF, is not backwards compatible with the old.
Note as well that the Indy machines are reserved for other use outside of tute times by a hierarchy of students starting at PhD, Masters, post-graduates, honours and finally, lastly, undergraduates. Please remember this and save the cost of a $50-00 fine. I don't want to have students complaining about lack of access to needed resources.


(3) When the compilation and linking has finished, we will explore some of the options provided for us by the Makefile. We can use the make -n command to indicate that we don't want make to actually do it, we just want it to tell us what it would do. (Also, at a later time, we can use man make ).

    make -n install 

make -n clean
make -n depend
make -n all

Note that there is no output from the last as the files are all up to date. Try

    touch main.c; make -n all 

touch mainheader.h; make -n all

Since touch changes the last modification date, the result of the first is hopefully obvious. The result of the second is because each of the .c files depends on the mainheader.h header file and hence will need to be recompiled.

(4) Run the program tute3a. It will bring up a white window with a black border. Note <alt>right-mouse button doesn't give a menu and using the normal buttons in this window will produce actions as though you had pressed the buttons in the root window. This is because the window has the root window as it's parent and it does not enable buton press events - these then get inherited by the parent. The root window's actions are as described in the last tutorial on Motif. Similarly, you cannot pop a window in front of this one since it is associated with the root window.

(5) Change the border width. How? Use your programming and analysis skills!

   grep -i border *.[ch] 


(Look for all occurrences of the word border ignoring case (-i) in all files with extensions of either .c or .h. This should give a good starting point for a search for changing the border). Edit the appropriate line.
Try swapping border colour to white and background to white.

(6) Try the following which has worked with our previous X programs:

    tute3a -fg blue 


If we have not programmed for this it will not work. Xt libraries actually take care of this for you. As you can see, there is a very large benefit in working at a higher level than (X) assembler!!

Note: Americans spell colour incorrectly and then insist on

propagating their errors to others. Beware of this!
Colormap not Colourmap,
DefaultColormap not DefaultColourmap,
XAllocColor not XAllocColour,
XParseColor not XParseColour

(7) Make clean.


(8) Copy tute3b from the graphics area, compile,run.

    mkdir ~/tute3b; cd ~/tute3b 

cp $g/tute3b/* .
xmkmf -a
make

Run tute3b and you will notice

 1) error messages

2) a colour window will appear with a quit button plus a number
of coloured buttons.

If you click on a coloured button, then its name and its colour index in the demo program will be displayed ( the index is purely internal).
The error messages :

    Couldn't lookup bright mustard

Couldn't lookup dark firebrick
Couldn't lookup miami pink
Couldn't lookup miami turquoise
Couldn't lookup dark brown
Couldn't lookup dark red
Couldn't allocate purple
Couldn't allocate medium purple
Couldn't allocate thistle

relate to not being able to find those colours in the rgb.txt database. What do you notice about the colours and the colour names? This is due to the error messages and the code. We will try to fix this later.

(9) Look at colour_demo.c (a listing is at the end of these tutorial sheets). Your tutor will go through the various parts.

(10) In colour_demo.c look at the #include lines. Change the following lines :

    #if 1

#include "colourheader.h" /* header file for colour */
#else
#include "greyheader.h" /* header file for grey */
#endif

to be #if 0. This will include the grey header file instead of the colour header file. You will probably need to do a make depend to properly recompile otherwise it will not know that the dependencies have changed. After the make depend, use make. Now run tute3b and you will see 101 different shades of grey - most PseudoColor workstations can probably show 256 different levels of grey but only the shown names are in the rgb.txt database.
Look at the file fine_grey_header.h and you will see another way of specifying colour. The format is #rrggbb and represent hexadecimal colours from 00 to ff. Edit colourdemo.c, change greyheader to fine_grey_header and recompile.
Notice that I have only put 42 colours in there - if I tried to get all 256 colours from the default colourmap then I would get failures since the map has already allocated some colours for the Window managers pretty window frames, etc.


(11) Let us now try to fix the problem of missing colours. Search for the string XAlloc - this is where the colours are allocated from the colour name array. Currently, if the colour doesn't exist or cannot be accomodated in the finite size colour map, it prints out a message but leaves the colour name there. If we change the "#if 0" to "#if 1" then we will set the colour to be black, and the name to be "Invalid colour". We also increment the col loop variable. Make these changes, recompile and rerun the example program.

(12) We can also look at enabling the colours whenever the cursor is over the colour box. We can allow a motion notify event to test to see if the cursor is over a colour box and update the colour name accordingly. We can cut and paste the code from PollEvents which tests for a colour and put it into the motion event test:

 if (InQuitBox(newx, newy))     /* inside quitbox*/

{
(void) InitFont (myDisplay,myGC, bigquitfont);
XDrawImageString (myDisplay, myWindow, myGC, QUITXSTR, QUITYSTR,
"Quit", strlen("Quit"));
}
----------------------------------------------------- new code here
else if (InGrid(newx, newy))
{
pos = CalculateColour(newx, newy);
WriteColourDetails (myDisplay, myWindow,myGC,pos);
}
-----------------------------------------------------
else /* not inside
{
(void) InitFont (myDisplay,myGC, smallquitfont);
XDrawImageString (myDisplay, myWindow, myGC, QUITXSTR, QUITYSTR,
"Quit", strlen("Quit"));
}
break;

Do this and recompile and test the code.

(13) If we want to have a Window Manager border around the window, then we need to set

    myWindowAttributes.override_redirect = False


This lets the window manager "manage" the window. Do this, recompile and run. You may now find that the code doesn't work properly. This is due to the fact that the window now needs to process Expose events. We will need to include ExposureMask into the XSelectInput call:

  XSelectInput (myDisplay, myWindow,

ExposureMask | ButtonPressMask | KeyPressMask | PointerMotionMask);

and we also now need to include an event action into our switch statement:

  case Expose :

DrawDisplay (myWindow, myGC);
break;

Add these and then recompile and rerun - all should be ok now.

(14) Make clean.


/*****************************************************************************

COLOURDEMO
AUTHOR: Renae BATINA
FILE: TUTORIALS.DIR/DEMOS.DIR/COLOURDEMO.C
INSTITUTION: Curtin University of Technology
Bentley, Western Australia
TO COMPILE: cc -o colourdemo colourdemo.c -lX11
Must have header file called colourheader.h
DESCRIPTION: This program takes a header file which contains
colours avaliable on the system in use. It then draws
all the colours in a grid. When the mouse button is
clicked on one of these colours, the name of the
colour will appear and the position of the colour
in the header file.
******************************************************************************/
/*
* INCLUDE FILES
*/
#include <X11/Xlib.h>
#include <stdio.h>
#include <X11/Xutil.h>
#if 1
#include "colourheader.h" /* header file for colour */
#else
#include "greyheader.h" /* header file for grey */
#endif
/*
* CONSTANT DECLARATIONS
*/
#define FALSE 0
#define TRUE 1
#define INVALID -1 /* invalid position */
#define BORDER 50 /* width of the border */
#define START BORDER*2 /* start position away from the boarder */
#define INCR BORDER /* how big the shaded grid lines are apart */
#define NUMACROSS 12 /* number of colours across the grid */
#define QUITXPOS BORDER /* x position of quit box */
#define QUITYPOS BORDER /* y position of quit box */
#define QUITWIDTH BORDER+BORDER/2 /* width of the quit box */
#define QUITHEIGHT BORDER/2 /* height of quit box */
#define QUITXSTR BORDER + 10 /* x position of quit string */
#define QUITYSTR 70 /* y position of quit string */
#define NUMXPOS 290 /* x position where to write array pos */
#define NUMYPOS 75 /* y position of all information */
#define COLXPOS 340 /* x position of colour name */

/******************************************************************************

WINDOW OPENWINDOW
******************************************************************************
DESCRIPTION: Creates a window with particular attributes and then maps this window
onto the screen. In addition to this, open_window also creates a
graphics context for the window which allows the window to be drawn to.
Xlib ROUTINES USED:
XCreateWindow Creates a window given particular attributes.
XDestroyWindow Unmaps a window and destroys it.
XFlush Flushes the buffer.
XMapWindow Draws a window to the screen.
XSetStandardProperties Sets the minimum set of properties for the
window manager.
OTHER ROUTINES USED:
createGC Function which return a graphics context for a window.
******************************************************************************/
Window OpenWindow(myDisplay,myScreen,myDepth,x, y, width, height, myGC,myWhitePixel,myBlackPixel)
Display *myDisplay; /* pointer to the display */
int myScreen; /* screen we are using */
int myDepth; /* colour plane depth */
int x, y; /* coords of top left corner of window */
unsigned int width, height; /* dimensions of the window */
GC *myGC; /* graphics context for the window */
unsigned long myWhitePixel; /* pixel value for white */
unsigned long myBlackPixel; /* pixel value for black */
{
int border_width = 20; /* border width of the window */
char *HEADING = "XColours";
XSetWindowAttributes myWindowAttributes; /* structure of window attibutes */
unsigned long myWindowMask; /* mask for window attributes */
XSizeHints theSizeHints; /* window hints for window manger */
static Window myWindow; /* window structure */
/* SET WINDOW ATTRIBUTES */
/* border colour */
myWindowAttributes.border_pixel = BlackPixel (myDisplay, myScreen);
/* background colour */
myWindowAttributes.background_pixel = WhitePixel (myDisplay, myScreen);
/* if window manager intervene or not */
myWindowAttributes.override_redirect = True;
/* create mask for attributes */
myWindowMask = CWBackPixel | CWBorderPixel | CWOverrideRedirect;
/* CREATE THE WINDOW */
myWindow = XCreateWindow (myDisplay, RootWindow (myDisplay, myScreen),
x, y, width, height, border_width,
myDepth, InputOutput, CopyFromParent,
myWindowMask, &myWindowAttributes);
/* SETUP HINTS FOR WINDOW MANAGER */
theSizeHints.flags = PPosition | PSize; /* set mask for the hints */
theSizeHints.x = x; /* x position */
theSizeHints.y = y; /* y position */
theSizeHints.width = width; /* width of the window */
theSizeHints.height = height; /* height of the window */
/* PASS HINTS TO WINDOW MANAGER */
XSetStandardProperties (myDisplay, myWindow, HEADING, HEADING, None,
NULL, 0, &theSizeHints);
/* SET GRAPHICS CONTEXT FOR THE WINDOW */
if (CreateGC (myDisplay,myWindow, myGC,myWhitePixel,myBlackPixel) == 0)
{
XDestroyWindow(myDisplay, myScreen);
return ((Window)0);
}
/* MAP WINDOW ONTO THE SCREEN */
XMapWindow (myDisplay, myWindow);
XFlush (myDisplay);
return(myWindow);
}

/*****************************************************************************

INT CREATEGC
****************************************************************************
DESCRIPTION: Creates a graphics context for a given window. It sets the
forground colour to black and the background colour to white.
If a GC cannot be created, then 0 is returned to the calling
routine, otherwise 1 is returned as well as the GC.
Xlib ROUTINES USED:
XCreateGC Create a new graphics context for a given
display with the depth of the specified
window.
XSetForeground Sets the forground colour in a graphics
context.
XSetBackground Sets the background colour in a graphics
context.
OTHER ROUTINES USED: None
*****************************************************************************/
int
CreateGC (myDisplay,myWindow, myGC,myBlackPixel,myWhitePixel)
/* This function creates a given graphic context for a given window */
Display *myDisplay; /* pointer to the display */
Window myWindow;
GC *myGC;
unsigned long myWhitePixel; /* pixel value for white */
unsigned long myBlackPixel; /* pixel value for black */
{
XGCValues myGCValues;
/*
* CREATE THE GRAPHICS CONTEXT
*/
*myGC = XCreateGC (myDisplay, myWindow,
(unsigned long) 0,
&myGCValues);
/*
* CHECK IF CREATED OK
*/
if (*myGC == 0)
return (0);
else
/* set forground and background defaults */
{
XSetForeground (myDisplay, *myGC, myBlackPixel);
XSetBackground (myDisplay, *myGC, myWhitePixel);
return (1);
}
}

/*****************************************************************************

VOID RECTANGLE
******************************************************************************
DESCRIPTION: Draws a rectangle with its top left corner at position x, y
and has dimensions of width and height.
To draw a box, width and height are the same.
Xlib ROUTINES USED:
XDrawRectangle Draws an outline of a rectangle.
******************************************************************************/
void
Rectangle (myDisplay,myWindow, myGC, x, y, width, height)
Display *myDisplay; /* pointer to the display */
Window myWindow; /* drawable window */
GC myGC; /* graphics context for the window */
int x, y; /* top left corner of the rectangle */
unsigned int width, height; /* dimensions of the rectangle */
{
XDrawRectangle (myDisplay, myWindow, myGC,
x, y, width, height);
}
/*****************************************************************************
VOID FILLRECTANGLE
*****************************************************************************
DESCRIPTION: Draws a filled rectangle with its top left corner at postion
x, y and with dimensions of width and height.
Xlib ROUTINES USED:
XFillRectangle Draws a filled rectangle.
*****************************************************************************/
void
FillRectangle (myDisplay,myWindow, myGC, x, y, width, height)
Display *myDisplay; /* pointer to the display */
Window myWindow; /* drawable window */
GC myGC; /* graphics context for the window */
int x, y; /* top left corner of the rectangle */
unsigned int width, height; /* dimensions of the rectangle */
{
XFillRectangle (myDisplay, myWindow, myGC,
x, y, width, height);
}

/******************************************************************************

VOID INIT
****************************************************************************
DESCRIPTION: First of all, this procedure establishes a connection
between the client and the X server. It then finds out
information about the display that the program is running on.
For example, it determines if the screen is colour or
monochrome.
Xlib ROUTINES USED:
BlackPixel Returns the black pixel value in the default
colour map
DefaultColormap Returns the default colour map for the
specified screen.
DefaultScreen Returns the integer specified by XOpenDisplay.
WhitePixel Returns the white pixel value in the default
colour map
XDisplayName Reports the display name.
XOpenDisplay Connects a client program with the server.
*******************************************************************************/
void init(myDisplay,myScreen,myDepth,myColourmap,myWhitePixel,myBlackPixel)
Display **myDisplay; /* pointer to the display */
int *myScreen; /* screen we are using */
int *myDepth; /* colour plane depth */
Colormap *myColourmap; /* systems default colour map */
unsigned long *myWhitePixel; /* pixel value for white */
unsigned long *myBlackPixel; /* pixel value for black */
{
/* MAKE CONNECTION WITH THE SERVER */
*myDisplay = XOpenDisplay ("");
if (*myDisplay == NULL)
{
fprintf (stderr,
"ERROR: Could not open a connection to X on display %s0,
XDisplayName (NULL));
exit (0);
}
/* INFORMATION ABOUT THE SCREEN */
*myScreen = DefaultScreen (*myDisplay);
/* FINDING THE NUMBER OF COLOUR PLANES AND GET THE DEFAULT COLOUR MAP */
*myDepth = DefaultDepth (*myDisplay, *myScreen);
*myColourmap = DefaultColormap (*myDisplay, *myScreen);
/* GET INFO FOR THE GRAPHICS CONTEXT */
*myWhitePixel = WhitePixel (*myDisplay, *myScreen);
*myBlackPixel = BlackPixel (*myDisplay, *myScreen);
}

/******************************************************************************

FONTSTRUCT *INITFONT
****************************************************************************
DESCRIPTION: Obtains information about a certian font and then stores
this information into a font structure for later use.
Xlib ROUTINES USED:
XLoadQueryFont Load a font and fill the font structure.
XSetFont Set the font into the given graphics context.
******************************************************************************/
XFontStruct *
InitFont (myDisplay,myGC, fontName)
Display *myDisplay; /* pointer to the display */
GC myGC; /* gc in which to set the font */
char fontName[]; /* name of the font to set */
{
XFontStruct *fontstruct; /* structure to fill with font info */
/* LOAD FONT */
fontstruct = XLoadQueryFont (myDisplay, fontName);
/* IF FONT OK, LOAD INFO INTO THE FONT STRUCTURE */
if (fontstruct != 0)
XSetFont (myDisplay, myGC, fontstruct->fid);
/* RETURN THE FONT STUCTURE */
return(fontstruct);
}

/*****************************************************************************

VOID INITCOLOURS
*****************************************************************************
DESCRIPTION: Initializes a series of colours and finds the hardware pixel value for them.
This value is stored in an array which can be accessed at anytime. This saves
program time as it does not need to continually look up the same colour.
Xlib ROUTINES USED:
XAllocColor Allocate a read only colourmap cell with
the closest hardware supported colour.
XLookupColor Get database RGB values and closest hardware
supported RGB values from the colour name
specified.
*****************************************************************************/
void InitColours(myDisplay, myColourmap,myDepth,colourpixels,myWhitePixel,myBlackPixel)
Display *myDisplay; /* pointer to the display */
Colormap myColourmap; /* systems default colour map */
int myDepth; /* colour plane depth */
unsigned long colourpixels[NUMCOLOURS];/* stores pixel values */
unsigned long myWhitePixel; /* pixel value for white */
unsigned long myBlackPixel; /* pixel value for black */
{
int col,loop; /* loop counter */
XColor hwarecolour; /* closest rgb colour for the hardware */
int status; /* determines if function ok */
/* COLOUR SCREEN */
if (myDepth > 1)
{
for (col=0,loop=0; loop<NUMCOLOURS;loop++ )
{
/* find a match for the english colour */
status = XParseColor (myDisplay, myColourmap,
greynames[loop], &hwarecolour);
if (status != 0)
{ /* allocate colour to colour map */
status = XAllocColor(myDisplay, myColourmap, &hwarecolour);
if (status != 0) /* set array of colours */
colourpixels[col++] = hwarecolour.pixel;
else
{
#if 0
colourpixels[col] = myBlackPixel;
greynames[col++] = "Invalid colour";
#endif
fprintf(stderr, "Couldn't allocate %s0, greynames[loop]);
}
}
else
{
#if 0
colourpixels[col] = myBlackPixel;
greynames[col++] = "Invalid colour";
#endif
fprintf(stderr, "Couldn't lookup %s0, greynames[loop]);
}
}
}
else /* MONOCHROME SCREEN */
for (loop = 0; loop < NUMCOLOURS-1; loop ++)
if (strcmp ("white", greynames[loop]) == 0)
colourpixels[loop] = myWhitePixel;
else
colourpixels[loop] = myBlackPixel;
}

/******************************************************************************

VOID SETCOLOUR
*****************************************************************************
DESCRIPTION: Sets the current drawing colour to the one specifed by number.
Number of the index into the array of the colour lookup
table.
Xlib ROUTINES USED:
XSetForeground Sets the forground colour in the graphics
context to the one specified.
******************************************************************************/
void
SetColour (myDisplay,myGC, colourpixels,number)
Display *myDisplay; /* pointer to the display */
GC myGC; /* the graphics context */
int number; /* index into the colour array */
unsigned long colourpixels[NUMCOLOURS];/* stores pixel values */
{
/* check if a valid number was given */
if ((number >= 0) && (number < NUMCOLOURS))
/* set the drawing colour */
XSetForeground (myDisplay, myGC, colourpixels[number]);
}
/*****************************************************************************
VOID CALCULATEWHERE
****************************************************************************
DESCRIPTION: Calculates the square which is the closest to where the
mouse click was made.
******************************************************************************/
void
CalculateWhere (oldx, oldy, newx, newy )
int oldx, oldy; /* position at where mouse is */
int *newx, *newy; /* position of closest top corner */
{
int tmp; /* temporary variables */
/* CALCULATE CLOSEST X COORDINATE */
tmp = BORDER;
while (tmp <= oldx)
{
tmp += INCR;
}
*newx = tmp - INCR;
/* CALCULATE CLOSEST Y COORDINATE */
tmp = BORDER;
while (tmp <= oldy)
{
tmp += INCR;
}
*newy = tmp - INCR;
}

/****************************************************************************

INT CALCULATECOLOUR
****************************************************************************
DESCRIPTION: Determines what colour square the mouse click was made on.
****************************************************************************/
int
CalculateColour(x, y)
int x, y;
{
int tmpx, tmpy, pos;
/*
* DONT INCLUDE THE BORDER
*/
tmpx = x - BORDER; tmpy = y - START;
/*
* CALCULATE NUMBER OF INCREMENTS IN FOR X
*/
if (tmpx != 0) x = tmpx/INCR;
else x = 0;
/*
* CALCULATE NUMBER OF INCREMENTS IN FOR Y
*/
if (tmpy != 0) y = tmpy/INCR;
else y = 0;
/* DETERMINE POSITION IN ARRAY */
pos = NUMACROSS*y + x;
/*
* DETERMINE IF VALID
*/
if (pos >= NUMCOLOURS) pos = INVALID;
return (pos);
}

/******************************************************************************

VOID WRITECOLOURDETAILS
*****************************************************************************
DESCRIPTION: Writes to the screen the name of the colour which has been
selected from the colour chart. It also writes the position
in the array the colour is located at.
Xlib ROUTINES USED:
XDrawImageString Draws an 8-bit image text characters.
OTHER ROUTINES USED:
InitFont Initializes the font with which to display
the text.
SetColour Sets the current drawing colour.
******************************************************************************/
void
WriteColourDetails (myDisplay, myWindow,myGC,pos)
Display *myDisplay; /* connection to X server */
Window myWindow; /* window ID */
GC myGC; /* the graphics context */
int pos; /* position in the array of colours */
{
XFontStruct *initfont(); /* function to get the font details */
char *font = "zapfchancery-mediumitalic.24";
char *blanks = " ";
char *invalid = "Invalid Choice";
char ch[3];
/*
* SET THE DRAWING COLOUR AND THE FONT TYPE
*/
(void)InitFont (myDisplay,myGC, font);
/*
* BLANK OUT THE PREVIOUS COLOUR
*/
XDrawImageString (myDisplay, myWindow, myGC, NUMXPOS-2, NUMYPOS,
blanks, strlen(blanks));
/*
* IF A VALID POSITION, WRITE THE NAME AND POSITION OF THE COLOUR
*/
if (pos != INVALID)
{
/* convert the integer position to a character */
sprintf (ch, "%d", pos);
XDrawImageString (myDisplay, myWindow, myGC, NUMXPOS, NUMYPOS,
ch, strlen(ch));
XDrawImageString (myDisplay, myWindow, myGC, COLXPOS, NUMYPOS,
greynames[pos], strlen(greynames[pos]));
}
/*
* ELSE, INFORM USER THAT AN INVALID CHOICE WAS MADE
*/
else
XDrawImageString (myDisplay, myWindow, myGC, COLXPOS, NUMYPOS,
invalid, strlen(invalid));
}

/*****************************************************************************

VOID DRAWDISPLAY
*****************************************************************************
DESCRIPTION: Draws the colour chart in the window with the appropriate
title and heading.
Xlib ROUTINES USED:
XDrawImageString Draws an 8-bit image text string.
XFlush Flush the contents of the buffer.
OTHER ROUTINES USED:
FillRectangle Draws a filled rectangle with the current
colour set.
InitFont Sets the font to write with.
Rectangle Draws the outline of a rectangle.
SetColour Sets the drawing colour.
******************************************************************************/
void DrawDisplay (myDisplay,myWindow, myGC,myWhitePixel,myBlackPixel,colourpixels)
Display *myDisplay; /* connection to X server */
Window myWindow;
GC myGC;
unsigned long myWhitePixel; /* pixel value for white */
unsigned long myBlackPixel; /* pixel value for black */
unsigned long colourpixels[NUMCOLOURS];/* stores pixel values */
{
int loop, count; /* loop counter */
int ypost; /* y position in the grid */
char *headingfont = "times-bold.32"; /* font for the heading */
char *heading = "X COLOURS"; /* heading of the window */
char *quitfont = "times-bold.17"; /* font for the quit box */
char *quit = "Quit"; /* inside quit box */
/* INITIALIZE VARIABLES */
ypost = START; count = 0;
/* LOOP TO DRAW ALL THE COLOURS */
for (loop=0; loop<NUMCOLOURS; loop++)
{
SetColour (myDisplay,myGC,colourpixels,loop);
FillRectangle (myDisplay,myWindow, myGC, BORDER+count*INCR, ypost, INCR, INCR);
if (count == NUMACROSS-1) /* start new line */
{
count = 0; ypost += INCR;
}
else
count++;
}
/* WRITE THE HEADING */
XSetBackground (myDisplay, myGC, myWhitePixel);
XSetForeground (myDisplay, myGC, myBlackPixel);
(void) InitFont (myDisplay,myGC, headingfont);
XDrawImageString (myDisplay, myWindow, myGC, 230, 35,
heading, strlen(heading));
/* DRAW THE QUIT BOX */
Rectangle (myDisplay,myWindow, myGC, QUITXPOS, QUITYPOS, QUITWIDTH, QUITHEIGHT);
(void)InitFont (myDisplay,myGC, quitfont);
XDrawImageString (myDisplay, myWindow, myGC, QUITXSTR, QUITYSTR,
quit, strlen(quit));
/* FLUSH THE BUFFER */
XFlush (myDisplay);
}

/***************************************************************************

INT INQUITBOX
* ***************************************************************************
DESCRIPTION: Determines if the mouse button has been moved into the rectangular 'QUIT' box.
***************************************************************************/
int
InQuitBox (xpos, ypos)
int xpos, ypos; /* current position of the mouse pointer */
{
if ( (xpos >= QUITXPOS) && (xpos <= QUITWIDTH+QUITXPOS) &&
(ypos >= QUITYPOS) && (ypos <= QUITHEIGHT+QUITYPOS) )
return (TRUE); /* inside the box */
else
return (FALSE); /* not inside the box */
}
/***************************************************************************
INT INGRID
****************************************************************************
DESCRIPTION: Determines if the mouse button was clicked inside the colour
grid or in the white space surrounding the colour grid.
***************************************************************************/
int InGrid (width,height,xpos, ypos)
int xpos, ypos; /* position the mouse button was clicked on */
unsigned int width, height; /* dimensions of the window */
{
if ( (xpos >= BORDER) && (xpos < width-BORDER) &&
(ypos >= START ) && (ypos < height-BORDER) )
return (TRUE); /* inside grid */
else
return (FALSE); /* in white space */
}

/****************************************************************************

VOID POLLEVENTS
****************************************************************************
DESCRIPTION: This procedure loops around until the user indicates to stop.
On each pass of the loop, if an event has occured, then
the correct action for that event will be carried out.
The user finishes the program by placing the mouse pointer
over the 'Quit' rectangle and presses any of the mouse buttons.
The events that the procedure recognises is any movement of
the mouse pointer and any button press of the mouse.
If the mouse is moved and motion is detected, then it is
determined if the mouse is over the 'Quit' box. If it is, then
the quit text enlargens to indicate that it has detected where
the mouse is. If it is not inside this box, the text is
returned to normal size.
If a mouse button is pressed, then once again, the program
determines if it was inside the 'Quit' box. If it is, then
this indicates that the user wishes to finish. However, if
it isn't and it is inside the colour grid, then the colour of
the square the pointer is in is determined and the colour and
position written to the screen. If the pointer is in 'white'
space, then an error message of 'Invalid Choice' is given.
Xlib ROUTINES USED:
XDrawImageString Draws an 8-bit image text character.
XNextEvent Gets the next event of any type or window.
XSelectInput Sets up the input types to be sent to a window
OTHER ROUTINES USED:
CalculateColour Determines the positon number in the array
the colour selected is.
CalculateWhere Determines the position of the mouse pointer
in relation to the grid of colours.
InitFont Initializes the font to use.
InGrid Determines if the position selected by the
mouse button is a valid position in the grid.
InQuitBox Function which determines if mouse pointer in
the quit box or not.
WriteColourDetails Writes to the screen in the correct position
the name of the colour selected and the postion
number it is in the array.
*****************************************************************************/
void
PollEvents (myDisplay,myWindow, myGC,width,height)
unsigned int width, height; /* dimensions of the window */
Display *myDisplay; /* connection to X server */
Window myWindow;
GC myGC;
{
int finished; /* if user wishes to quit */
XEvent myEvent; /* event which has occured */
int newx, newy; /* position of mouse pointer */
int pos;
/* font information */
char *bigquitfont = "times-bold.18";
char *smallquitfont = "times-bold.17";

/*

* SELECT WHICH EVENTS YOU WANT TO WATCH
*/
XSelectInput (myDisplay, myWindow,
ButtonPressMask | KeyPressMask | PointerMotionMask);
finished = FALSE; /* initialize loop control */
/*
* START POLLING FOR EVENTS
*/
while (!finished)
{
/* read next event in the queue */
XNextEvent (myDisplay, &myEvent);
switch (myEvent.type)
{
/* mouse was moved */
case MotionNotify :
CalculateWhere (myEvent.xmotion.x, myEvent.xmotion.y,
&newx, &newy);
if (InQuitBox(newx, newy)) /* inside quitbox*/
{
(void) InitFont (myDisplay,myGC, bigquitfont);
XDrawImageString (myDisplay, myWindow,
myGC, QUITXSTR, QUITYSTR,
"Quit", strlen("Quit"));
}
else /* not inside quitbox*/
{
(void) InitFont (myDisplay,myGC, smallquitfont);
XDrawImageString (myDisplay, myWindow,
myGC, QUITXSTR, QUITYSTR,
"Quit", strlen("Quit"));
}
break;
/* mouse button was pressed */
case ButtonPress:
CalculateWhere (myEvent.xbutton.x, myEvent.xbutton.y,
&newx, &newy);
/* user wishes to finish program */
if (InQuitBox(newx, newy)) finished = TRUE;
/* determine if valid position on the grid */
else if (InGrid(width,height,newx, newy))
{
pos = CalculateColour(newx, newy);
WriteColourDetails (myDisplay, myWindow,myGC,pos);
}
else /* in white space */
{
pos = INVALID;
WriteColourDetails (myDisplay, myWindow,myGC,pos);
}
break;
}
}
}

/*****************************************************************************

MAINLINE
******************************************************************************/
main (argc, argv)
int argc;
char **argv;
{
/* DECLARATIONS */
int x = 250; /* x top left corner of window */
int y = 25; /* y top left corner of window */
unsigned int width, height; /* dimensions of the box */
Display *myDisplay; /* pointer to the display */
int myScreen; /* screen we are using */
int myDepth; /* colour plane depth */
Window myWindow; /* Window to display */
Colormap myColourmap; /* systems default colour map */
GC myGC;
unsigned long myWhitePixel; /* pixel value for white */
unsigned long myBlackPixel; /* pixel value for black */
unsigned long colourpixels[NUMCOLOURS];/* stores pixel values */
/* SET THE DIMENSIONS OF THE BOX */
width = NUMACROSS*INCR+START;
height = NUMCOLOURS/NUMACROSS*INCR+2*START;
/* INITIALIZE VARIABLES */
init(&myDisplay,&myScreen,&myDepth,&myColourmap,&myWhitePixel,&myBlackPixel);
InitColours(myDisplay,myColourmap,myDepth,colourpixels,myWhitePixel,myBlackPixel);
/* OPEN UP A WINDOW */
myWindow = OpenWindow(myDisplay,myScreen,myDepth,x, y, width, height, &myGC,myWhitePixel,myBlackPixel);
/* DO SOME DRAWING IN COLOUR */
DrawDisplay (myDisplay,myWindow, myGC,myWhitePixel,myBlackPixel,colourpixels);
/* POLL FOR EVENTS */
PollEvents (myDisplay,myWindow, myGC,width,height);
/* DRAW VIA FLUSHING THE BUFFERS */
XFlush (myDisplay);
/* DESTROY ALL WINDOWS */
XDestroyWindow (myDisplay, myWindow);
XCloseDisplay (myDisplay);
/* EXIT */
exit (0);
}
/*****************************************************************************
END OF FILE COLOURDEMO.C
*****************************************************************************/