Question:
I'm trying to change the cursor from an arrow to a watch, but I cannot find a call to do that.
There are a number of ways to create and display cursors. In essence, a cursor
is simply an X image (XImage) which follows the pointer. As such, it is possible to
create a cursor out of just about anything which is XImage based. This includes
arbitrary font characters, and bitmaps.
X has a built-in set of cursor types which are indeed implemented using a
standard font. A Cursor as a type is just an opaque handle associated
with the particular XImage.
You can have as many cursors as you like: simply install a particular cursor
when needed. Note that cursors are inherited through the widget hierarchy:
in many cases all that is required is to install a cursor on the
shell widget representing the dialog where the cursor is needed.
The file <X11/cursorfont.h> defines a set of offsets into the Standard Cursor Font.
In order to use and apply one of the standard cursors, it is necessary to perform two steps.
-
Firstly, the Cursor must be loaded into the X server
-
Secondly, the Cursor must be applied to the Window where it is required
A Standard Font Cursor is loaded using the routine XCreateFontCursor(), which is formally defined as
follows:
void XCreateFontCursor (Display *display, int offset)
Here the offset parameter is an index into the set of standard font characters.
For example, to load the watch cursor from the Standard Font, we simply look up the index associated
with the watch cursor (XC_watch) in the <X11/cursorfont.h> file, and then apply the above routine.
The following code is all that is required:
#include <X11/cursorfont.h>
...
extern Display *display;
Cursor watch = XCreateFontCursor (display, XC_watch) ;
Once the Cursor has been created/loaded, we can now install it on a Window.
The routine to perform this step is XDefineCursor(), which is
formally specified as follows:
void XDefineCursor (Display *display,
Window window,
Cursor cursor)
Typically, the two steps are wrapped up into a single function. For example, the following
two routines can be used to set the cursor to a watch, and subsequently restore the
cursor to the default (a left pointing arrow). Usually, the widget parameter is a shell widget,
so that the watch is applied by default to the whole dialog.
static Cursor watch_cursor = (Cursor) 0 ;
static Cursor normal_cursor = (Cursor) 0 ;
void SetWatchCursor (Widget widget)
{
if (watch_cursor == (Cursor) 0) {
watch_cursor = XCreateFontCursor (XtDisplay(widget), XC_watch) ;
}
XDefineCursor (XtDisplay (widget), XtWindow (widget), watch_cursor) ;
}
void SetNormalCursor (Widget widget)
{
if (normal_cursor == (Cursor) 0) {
normal_cursor = XCreateFontCursor (XtDisplay (widget), XC_left_ptr) ;
}
XDefineCursor (XtDisplay(widget), XtWindow (widget), normal_cursor) ;
}
There are other ways of going about this: instead of explicitly assigning the left pointer to a Window
when restoring the "normal" cursor, it is also possible to undefine a cursor
using the routine XUndefineCursor(), so that the cursor associated with a given Window is
again inherited from its parent. XUndefineCursor() is specified as follows:
void XUndefineCursor (Display *display, Window window)
Cursors can be created out of any Font or Pixmap. The routine XCreateGlyphCursor()
will create a cursor from a source and optionally a mask Font character (which do not have to be even in
the same Font). XCreatePixmapCursor() is similar, except you can create a cursor out of a bitmap (or
a couple of bitmaps, if using a mask). These routines are defined as follows:
Cursor XCreatePixmapCursor (Display *display,
Pixmap source,
Pixmap mask,
XColor *foreground,
XColor *background,
unsigned int hotspot_x,
unsigned int hotspot_y)
Cursor XCreateGlyphCursor (Display *display,
Font source,
Font mask,
unsigned int source_index,
unsigned int mask_index,
XColor *foreground,
XColor *background)
Since both utilities require the creation and manipulation of several X data types
(XColor, Font, Pixmap), a complete example of each cannot really be given in the space available.
A brief example of XCreateGlyphCursor() is however given below.
The color of a cursor can be modified through the routine XRecolorCursor(), defined
as follows:
void XRecolorCursor (Display *display,
Cursor cursor,
XColor *foreground,
XColor *background)
An XColor is simply a structure describing the red, green, blue (RGB) components of
a color. Suppose we have an arbitrary Cursor, and a couple of Pixels. We could color
the cursor by some code similar to the following example fragments:
/* A routine to (roughly) convert from a Pixel to an XColor */
void PixelToXColor(Display *display, Pixel pixel, XColor *xp)
{
Colormap cmap = XDefaultColormap(display, DefaultScreen(display)) ;
xp->pixel = pixel ;
xp->flags = DoRed | DoGreen | DoBlue ;
XQueryColor(display, cmap, xp) ;
}
/* A routine to color a Cursor, given a couple of Pixels */
void ColorCursor(Display *display, Cursor cursor, Pixel fg, Pixel bg)
{
XColor fg_internal ;
XColor bg_internal ;
PixelToXColor(display, fg, &fg_internal) ;
PixelToXColor(display, bg, &bg_internal) ;
XRecolorCursor(display, cursor, &fg_internal, &bg_internal) ;
}
Note that the Standard Cursor Font routine XCreateFontCursor() creates cursors which are black and white.
However, it is possible to write a routine to create a cursor from the Standard Cursor Font in a particular color,
since XCreateFontCursor() is nothing more than a wrapper onto XCreateGlyphCursor(). For example, we could define
a new routine as follows:
Cursor CreateColoredStandardCursor (Display *display, int offset, XColor *fg, XColor *bg)
{
/*
** The Standard Cursor Font contains the shape glyph followed by the mask glyph.
** This is why definitions in <X11/cursorfont.h> increment by 2.
*/
if (display->cursor_font == None) {
/* Load the Standard Cursor Font */
display->cursor_font = XLoadFont (display, "cursor") ;
if (display->cursor_font == None) {
return None ;
}
}
return XCreateGlyphCursor (display,
display->cursor_font, /* Shape Font */
display->cursor_font, /* Mask Font */
offset, /* Shape Character Offset */
offset + 1, /* Mask Character Offset */
fg,
bg) ;
}
Like all resources consumed by the X server and clients, Cursors should be deallocated
when no longer required. The routine XFreeCursor() performs this task, and it
is formally defined as follows:
void XFreeCursor (Display *display, Cursor cursor)
Note that a Cursor is applied to a particular Window, and so that it follows
that it is not possible to define cursors for individual Gadgets, since
they inherit a Window from their parent. Supposedly you could track pointer motion
in the Gadget's parent, and define a cursor for the parent when the pointer is "over" a Gadget,
although since the Manager class is already packed up with all sorts of event mechanisms as
part of the Gadget implementation, this is more than likely to be somewhat expensive.
Secondly, depending on the nature of your application
and environment, you may find that you have to explicitly flush the X queue (XFlush())
after defining a Cursor on a Window, so that the effect is immediate. XFlush() is specified
as follows:
void XFlush (Display *display)
The Standard Cursor Font is listed in a number of places,
including the following:
Xlib Reference Manual,
Edited by Adrian Nye,
O'Reilly and Associates, Inc.,
ISBN 1-56592-006-6
Buy it from Amazon.com or Amazon.co.uk
In particular, you should look at Appendix I, which is on page 891 in the Third Edition.
Sponsored
by X-Designer - The Leading X/Motif GUI Builder
- Click to download a FREE evaluation
Goto top of page
|