|
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
mkdir ~/tute3a; cd ~/tute3a
cp $g/tute3a/*.c $g/tute3a/*.h $g/tute3a/Imakefile .
(Make sure you DO include the dot at the end).
(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)
(1) Try
xmkmf; more Makefile
(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
xmkmf -a
make
-lX11_s : shared (_s) X11 Lib routines.
This library may have a different name on different platforms
Students at Curtin.
(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
touch main.c; make -n all
touch mainheader.h; make -n all
(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]
(6) Try the following which has worked with our previous X programs:
tute3a -fg blue
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
(8) Copy tute3b from the graphics area, compile,run.
mkdir ~/tute3b; cd ~/tute3b
cp $g/tute3b/* .
xmkmf -a
make
1) error messages
2) a colour window will appear with a quit button plus a number
of coloured buttons.
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
(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
(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;
(13) If we want to have a Window Manager border around the window, then we need to set
myWindowAttributes.override_redirect = False
XSelectInput (myDisplay, myWindow,
ExposureMask | ButtonPressMask | KeyPressMask | PointerMotionMask);
case Expose :
DrawDisplay (myWindow, myGC);
break;
(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
*****************************************************************************/