Department of Engineering

IT Services

Rectangles, lines, dots, arcs and text

First, some elemental structures.

typedef struct 
{
    short x, y; 
} XPoint;

typedef struct 
{
    short x1, y1,x2,y2;
} XSegment;

typedef struct 
{
    short x, y;
    unsigned short width, height;
} XRectangle;

typedef struct  
{
    short x, y; 
    unsigned short width, height;
    short angle1,angle2;
} XArc;

The following routines make extensive use of the GC (refer to the manual for further information on exactly which components are relevant). Lines of width 0 come out with a thickness of 1 drawn using a different, faster, algorithm.

They write to drawables (pixmaps or windows that can accept graphic input).

XDrawPoint(display,d,gc,x,y)
XDrawPoints(display,d,gc,points,npoints,mode)
     int mode; /* CoordModeOrigin or CoordModePrevious */

XDrawLine(display,d,gc,x1, y1, x2, y2)
XDrawLines(display,d,gc,points.npoints,mode)
     int mode; /* CoordModeOrigin or CoordModePrevious */

XDrawSegments(display,d,gc,segments,nsegments)

XDrawRectangle(display,d,gc,x,y,width,height)  
XDrawRectangles(display,d,gc,rectangles,nrectangles) 

XDrawArc(display,d,gc,x,y,width,height,angle1,angle2)
    unsigned int width,height /*major and minor axes of arc*/
    int angle1 /*start of arc, clockwise from 3 o'clock,scaled by 64 */   
    int angle2 /*path and extent of arc, relative to angle1, scaled by 64*/
XDrawArcs(display,d,gc,arcs,narcs)                           

XFillRectangle(display,d,gc,x,y,width,height)                
XFillRectangles(display,d,gc,rectangles,nrectangles)

The last 2 routines fill rectangles that are 1 pixel shorter and narrower than the XDrawRectangle routines.

XFillPolygon(display,d,gc,points,npoints,shape,mode)         
    int shape /*Complex,Convex,NonConvex ;
               helps select best fill algorithm */
    int mode; /* CoordModeOrigin or CoordModePrevious */
XFillArc(display,d,gc,x,y,width,height,angle1,angle2)
XFillArcs(display,d,gc,arcs,narcs)  

XMoveArea(display, w, srcX, srcY, dstX, dstY, width, height)
    int srcX, srcY;    /* position of top LH corner of area    */
    int dstX, dstY;    /* where top LH corner must end up      */
    int width, length; /* size of area to be moved             */

XCopyArea(display,src,dest,gc,src_x, src_y,width, height, dest_x,dest_y)
    Drawable src_x, src_y;    /* position of top LH corner of area    */
    int src_x,src_y,dest_x, dest_y; /* where top LH corner must end up */
    unsigned int width, height; /* size of area being copied            */
             /* The depth of the source and destination must be the same. */

XCopyPlane(display,src,dest,gc,src_x,src_y,width,height,dest_x,dest_y,plane)
             /* src and dest are drawables with the same root */
    unsigned int width,height;
    unsigned long plane;

XClearArea(display,w,x,y,width,height,exposures)
    int width, height;/* if width=0 then width is set to window_width-x 
                         and similarly for y */
    Bool exposures;   /* if True then exposure events generated */

XClearWindow(display,w) /* clears the window */

Drawing Text in a Window

The simplest way to use a font is to call XLoadQueryfont which loads the font and returns a pointer to a XFontStruct structure which it fills. The fid field is what you use when setting the current font.

typedef struct {                                                    
    XExtData    *ext_data;      /* hook for extension to hang data */
    Font        fid;            /* Font id for this font */         
    unsigned    direction;      /* direction the font is painted */ 
    unsigned    min_char_or_byte2;/* first character */             
    unsigned    max_char_or_byte2;/* last character */              
    unsigned    min_byte1;      /* first row that exists */         
    unsigned    max_byte1;      /* last row that exists */          
    Bool        all_chars_exist;/* flag if all characters exist*/   
    unsigned    default_char;   /* char to print for undefined character */
    int         n_properties;   /* how many properties there are */    
    XFontProp   *properties;    /* pointer to additional properties*/  
    XCharStruct min_bounds;     /* minimum bounds over all existing char*/
    XCharStruct max_bounds;     /* minimum bounds over all existing char*/
    XCharStruct *per_char;      /* first_char to last_char information */
    int         ascent;         /* log. extent baseline for spacing */ 
    int         descent;        /* log. descent baseline for spacing */
} XFontStruct;

XFontStruct *XLoadQueryFont(display,name)  /* prepare a font for action       */
    char *name;          /* name of the font */

XFreeFont(display,font_struct)    /* tells the server that this font is no */
    XFontStruct *font_struct;     /* longer needed, and frees resources.   */

  figure284
Figure 2: Font dimensions

Finding the Width of Characters

This can be done for 8 and 16 bit characters.

int XTextWidth(font_struct,str, count)
    char *str;           /* string */
    XFontStruct *font_struct;  /* font-id of font to use */

int XTextWidth16(font_struct,str, count)
    char *str;           /* string */
    XFontStruct *font_struct;  /* font-id of font to use */

XTextExtents(font_struct,string,nchars,direction,ascent,descent,overall)
    XFontStruct *font_struct;
    char *str;           /* string            */
    int *direction, *ascent, *descent; /*returned dimensions */
    XCharStruct     *overall; /* overall retured dimensions */

XTextExtents16(font_struct,string,nchars,direction,ascent,descent,overall)

Printing Characters on the Screen

For strings of a single font use

XDrawString(display,d,gc,x, y,string,length)
XDrawImageString(display,d,gc,x, y,string,length) /*draws background too*/
XDrawImageString16(display,d,gc,x, y,string,length) /*draws background too*/
Otherwise the text to be output needs to be held in the following structure:-
typedef struct {
    char *chars;    /* pointer to string */
    int nchars;     /* number of characters */
    int delta;      /* delta between strings */
    Font font;      /* font to print it in, None don't change */
} XTextItem;

XDrawText(display,d,gc,x, y,items,nitems)
    XTextItem *items;
XDrawText16(display,d,gc,x, y,items,nitems)
    XTextItem *items;

Creating Cursors

X provides a automatic facility whereby a cursor may be registered for each window and whenever the mouse is in that window it will take on the correct shape. If a special cursor has not been registered for a window the mouse will use the parent-window's cursor.

There are three cursor creating routines. The 1st is much the easiest:- (check in <X11/cursorfont.h> for shape names, or use the xcursors program if available)

Cursor XCreateFontCursor(display,shape);

The utility bitmap is useful for designing bitmaps if you want a cursor which is not in the standard library. Such cursors are defined in terms of two bitmaps and two pixel values. The cursor bitmap determines the shape of the cursor using the display function and the foreground and background pixel values, while the mask bitmap determines the area which the cursor is permitted to modify. Every cursor has a hot-spot which determines the coordinates of the point on the screen where the X server considers it to be. The relative coordinates of this point are also given at this stage.

Cursor XCreateGlyphCursor(display,sfont,mfont,schar,mchar,scolor,bcolor)
   Font sfont;               /* font glyph for cursor*/
   Font mfont;               /* mask font*/       
   unsigned int schar;       /* shape of cursor*/ 
   unsigned int mchar;       /* mask character */ 
   XColor *scolor;            /* RGB foreground */
   XColor *bcolor;            /* RGB background */

Cursor XCreatePixmapCursor(display,source,mask,scolor,bcolor,x,y)
   Pixmap source;
   Pixmap mask;
   XColor *scolor;
   XColor *bcolor;
   unsigned int x,y;

XFreeCursor(display,cursor) /* REMOVE A CURSOR PREVIOUSLY GENERATED */
    Cursor cursor;

XDefineCursor(display,w, cursor)
    Cursor cursor; /*use this cursor when pointer is in window */

XUndefineCursor(display,w) /*mouse will use parent's cursor  */

Examples

Hit any key to quit from this program.

 

/* compile using cc -I/usr/include/X11R5 -L/usr/lib/X11R5 -o demo demo.c -lX11 */
#include <stdio.h>
#include <X11/Xlib.h>
 /* This program draws a red line and some text in a chosen font.
  * 
  */
     Display *display;
     Window  window;
     XSetWindowAttributes attributes;
     XGCValues gr_values;
     XFontStruct *fontinfo;
     GC gr_context;
     Visual *visual;
     int depth;
     int screen;
     XEvent event;
     XColor    color, dummy;
 
main (argc, argv)
char   *argv[];
int     argc;
{
     display = XOpenDisplay(NULL);
     screen = DefaultScreen(display);
     visual = DefaultVisual(display,screen);
     depth  = DefaultDepth(display,screen);
     attributes.background_pixel = XWhitePixel(display,screen);
 
     window = XCreateWindow( display,XRootWindow(display,screen),
                            200, 200, 350, 200, 5, depth,  InputOutput,
                            visual ,CWBackPixel, &attributes);
     XSelectInput(display,window,ExposureMask | KeyPressMask) ;
     fontinfo = XLoadQueryFont(display,"6x10");
     
     XAllocNamedColor(display, DefaultColormap(display, screen),"red",
                      &color,&dummy);
 
     gr_values.font = fontinfo->fid;
     gr_values.foreground = color.pixel;
     gr_context=XCreateGC(display,window,GCFont+GCForeground, &gr_values);
     XFlush(display);
     XMapWindow(display,window);
     XFlush(display);

     while(1){
        XNextEvent(display,&event);

        switch(event.type){
        case Expose:
             XDrawLine(display,window,gr_context,0,0, 100, 100);
             XDrawString(display,window,gr_context,100,100,"hello",5);
             break;
        case KeyPress: 
             XCloseDisplay(display); 
             exit(0);

        }
     }
}

Here is a program that uses more of the aforementioned routines.  

#include  <X11/cursorfont.h> 
#include <stdio.h> 
#include <X11/Xlib.h> 
  
 main (argc, argv) 
 char   *argv[]; 
 int     argc; 
 { 
      Display *display; 
      Window  win1; 
      XEvent event;
      XSetWindowAttributes attributes; 
      Cursor cursor_shape; 
      XFontStruct *fontinfo; 
      GC gr_context1, gr_context2; 
      XGCValues gr_values; 
      int     screen; 
      int     i; 
  
      display = XOpenDisplay(NULL); 
      screen  = XDefaultScreen(display);
  
      attributes.background_pixel      = XWhitePixel(display,screen); 
      attributes.border_pixel          = XBlackPixel(display,screen); 
  
      win1= XCreateWindow( display,XRootWindow(display,screen),0,200, 
                           XDisplayWidth(display,screen)-400,
                           XDisplayHeight(display,screen)-400,5, 6,
                           InputOutput, XDefaultVisual(display,screen),
                           CWBackPixel| CWBorderPixel, &attributes);

      XSelectInput(display,win1,ExposureMask | KeyPressMask) ;
  
      gr_values.function =   GXcopy; 
      gr_values.plane_mask = AllPlanes; 
      gr_values.foreground = BlackPixel(display,screen); 
      gr_values.background = WhitePixel(display,screen); 
      gr_context1=XCreateGC(display,win1, 
                  GCFunction | GCPlaneMask | GCForeground | GCBackground, 
                  &gr_values); 
  
      gr_values.function =   GXxor; 
      gr_values.foreground = WhitePixel(display,screen); 
      gr_values.background = BlackPixel(display,screen); 
      gr_context2=XCreateGC(display,win1, 
                  GCFunction | GCPlaneMask | GCForeground | GCBackground, 
                  &gr_values); 
  
      fontinfo = XLoadQueryFont(display,"6x10"); 
  
      cursor_shape=XCreateFontCursor(display,XC_heart); 
      XDefineCursor(display,win1,cursor_shape); 
  
      XSetFont(display,gr_context1,fontinfo->fid); 
      XSetFont(display,gr_context2,fontinfo->fid); 
  
      XMapWindow(display,win1); 

      while(1){
        XNextEvent(display,&event);

        switch(event.type){
        case Expose:
             XClearWindow(display,win1);
             XDrawString(display,win1,gr_context1,50,50,"Hello",5); 
             XDrawImageString(display,win1,gr_context2,20,20,"Hello",5); 
  
             XFillRectangle(display,win1,gr_context1,150,150,111,111); 
             XFillRectangle(display,win1,gr_context2,200,180,111,111); 
             break;
        case KeyPress: 
             XCloseDisplay(display); 
             exit(0);
        }
     }
}