diff options
Diffstat (limited to 'unix/tkUnixCursor.c')
-rw-r--r-- | unix/tkUnixCursor.c | 387 |
1 files changed, 319 insertions, 68 deletions
diff --git a/unix/tkUnixCursor.c b/unix/tkUnixCursor.c index 858025c..e3873a7 100644 --- a/unix/tkUnixCursor.c +++ b/unix/tkUnixCursor.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixCursor.c,v 1.7 2005/10/21 01:51:45 dkf Exp $ + * RCS: @(#) $Id: tkUnixCursor.c,v 1.8 2006/12/17 00:43:06 mdejong Exp $ */ #include "tkPort.h" @@ -116,12 +116,89 @@ static struct CursorName { }; /* + * The table below is used to map from a cursor name to the data + * that defines the cursor. This table is used for cursors defined + * by Tk that don't exist in the X cursor table. + */ + +#define CURSOR_NONE_DATA \ +"#define none_width 1 + #define none_height 1 + #define none_x_hot 0 + #define none_y_hot 0 + static unsigned char none_bits[] = { + 0x00};" + + +/* Define test cursor to check that mask + * fg and bg color settings are working. + * + * . configure -cursor {center_ptr green red} + * + * . configure -cursor {@myarrow.xbm myarrow-mask.xbm green red} + * + * . configure -cursor {myarrow green red} + */ + +/*#define DEFINE_MYARROW_CURSOR*/ + + +#ifdef DEFINE_MYARROW_CURSOR + +#define CURSOR_MYARROW_DATA \ +"#define myarrow_width 16 +#define myarrow_height 16 +#define myarrow_x_hot 7 +#define myarrow_y_hot 0 +static unsigned char myarrow_bits[] = { + 0x7f, 0xff, 0xbf, 0xfe, 0xdf, 0xfd, 0xef, 0xfb, 0xf7, 0xf7, 0xfb, 0xef, + 0xfd, 0xdf, 0xfe, 0xbf, 0x80, 0x00, 0xbf, 0xfe, 0xbf, 0xfe, 0xbf, 0xfe, + 0xbf, 0xfe, 0xbf, 0xfe, 0xbf, 0xfe, 0x3f, 0xfe};" + +#define CURSOR_MYARROW_MASK \ +"#define myarrow-mask_width 16 +#define myarrow-mask_height 16 +#define myarrow-mask_x_hot 7 +#define myarrow-mask_y_hot 0 +static unsigned char myarrow-mask_bits[] = { + 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x1f, + 0xfe, 0x3f, 0xff, 0x7f, 0xff, 0xff, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, + 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01};" + +#endif /* DEFINE_MYARROW_CURSOR */ + + +static struct TkCursorName { + char *name; + char *data; + char *mask; +} tkCursorNames[] = { + + {"none", CURSOR_NONE_DATA, NULL}, + +#ifdef DEFINE_MYARROW_CURSOR + {"myarrow", CURSOR_MYARROW_DATA, CURSOR_MYARROW_MASK}, +#endif /* DEFINE_MYARROW_CURSOR */ + + {NULL, NULL, NULL} +}; + +/* * Font to use for cursors: */ #ifndef CURSORFONT #define CURSORFONT "cursor" #endif + +MODULE_SCOPE Cursor CreateCursorFromTableOrFile( + Tcl_Interp *interp, + Tk_Window tkwin, + int argc, + CONST char **argv, + struct TkCursorName *tkCursorPtr); + + /* *---------------------------------------------------------------------- @@ -152,9 +229,9 @@ TkGetCursorByName( Cursor cursor = None; int argc; CONST char **argv = NULL; - Pixmap source = None; - Pixmap mask = None; Display *display = Tk_Display(tkwin); + int inTkTable = 0; + struct TkCursorName* tkCursorPtr = NULL; if (Tcl_SplitList(interp, string, &argc, &argv) != TCL_OK) { return NULL; @@ -162,7 +239,28 @@ TkGetCursorByName( if (argc == 0) { goto badString; } + + /* + * Check Tk specific table of cursor names. The + * cursor names don't overlap with cursors defined + * in the X table so search order does not matter. + */ + if (argv[0][0] != '@') { + for ( tkCursorPtr = tkCursorNames; ; tkCursorPtr++) { + if (tkCursorPtr->name == NULL) { + tkCursorPtr = NULL; + break; + } + if ((tkCursorPtr->name[0] == argv[0][0]) && + (strcmp(tkCursorPtr->name, argv[0]) == 0)) { + inTkTable = 1; + break; + } + } + } + + if ((argv[0][0] != '@') && !inTkTable) { XColor fg, bg; unsigned int maskIndex; register struct CursorName *namePtr; @@ -188,6 +286,7 @@ TkGetCursorByName( break; } } + maskIndex = namePtr->shape + 1; if (argc == 1) { fg.red = fg.green = fg.blue = 0; @@ -220,15 +319,11 @@ TkGetCursorByName( dispPtr->cursorFont, namePtr->shape, maskIndex, &fg, &bg); } else { - int width, height, maskWidth, maskHeight; - int xHot, yHot, dummy1, dummy2; - XColor fg, bg; - /* * Prevent file system access in safe interpreters. */ - if (Tcl_IsSafe(interp)) { + if (!inTkTable && Tcl_IsSafe(interp)) { Tcl_AppendResult(interp, "can't get cursor from a file in", " a safe interpreter", NULL); cursorPtr = NULL; @@ -236,65 +331,22 @@ TkGetCursorByName( } /* - * The cursor is to be created by reading bitmap files. There should - * be either two elements in the list (source, color) or four (source - * mask fg bg). + * If the cursor is to be created from bitmap files, then there + * should be either two elements in the list (source, color) + * or four (source mask fg bg). A cursor defined in the Tk + * table accepts the same arguments as an X cursor. */ - if ((argc != 2) && (argc != 4)) { + if (inTkTable && (argc != 1) && (argc != 2) && (argc != 3)) { goto badString; } - if (TkReadBitmapFile(display, - RootWindowOfScreen(Tk_Screen(tkwin)), &argv[0][1], - (unsigned int *) &width, (unsigned int *) &height, - &source, &xHot, &yHot) != BitmapSuccess) { - Tcl_AppendResult(interp, "cleanup reading bitmap file \"", - &argv[0][1], "\"", NULL); - goto cleanup; - } - if ((xHot < 0) || (yHot < 0) || (xHot >= width) || (yHot >= height)) { - Tcl_AppendResult(interp, "bad hot spot in bitmap file \"", - &argv[0][1], "\"", NULL); - goto cleanup; - } - if (argc == 2) { - if (XParseColor(display, Tk_Colormap(tkwin), argv[1], &fg) == 0) { - Tcl_AppendResult(interp, "invalid color name \"", - argv[1], "\"", NULL); - goto cleanup; - } - cursor = XCreatePixmapCursor(display, source, source, - &fg, &fg, (unsigned) xHot, (unsigned) yHot); - } else { - if (TkReadBitmapFile(display, - RootWindowOfScreen(Tk_Screen(tkwin)), argv[1], - (unsigned int *) &maskWidth, (unsigned int *) &maskHeight, - &mask, &dummy1, &dummy2) != BitmapSuccess) { - Tcl_AppendResult(interp, "cleanup reading bitmap file \"", - argv[1], "\"", NULL); - goto cleanup; - } - if ((maskWidth != width) && (maskHeight != height)) { - Tcl_SetResult(interp, - "source and mask bitmaps have different sizes", - TCL_STATIC); - goto cleanup; - } - if (XParseColor(display, Tk_Colormap(tkwin), argv[2], - &fg) == 0) { - Tcl_AppendResult(interp, "invalid color name \"", argv[2], - "\"", NULL); - goto cleanup; - } - if (XParseColor(display, Tk_Colormap(tkwin), argv[3], - &bg) == 0) { - Tcl_AppendResult(interp, "invalid color name \"", argv[3], - "\"", NULL); - goto cleanup; - } - cursor = XCreatePixmapCursor(display, source, mask, - &fg, &bg, (unsigned) xHot, (unsigned) yHot); + + if (!inTkTable && (argc != 2) && (argc != 4)) { + goto badString; } + + cursor = CreateCursorFromTableOrFile(interp, tkwin, + argc, argv, tkCursorPtr); } if (cursor != None) { @@ -307,12 +359,6 @@ TkGetCursorByName( if (argv != NULL) { ckfree((char *) argv); } - if (source != None) { - Tk_FreePixmap(display, source); - } - if (mask != None) { - Tk_FreePixmap(display, mask); - } return (TkCursor *) cursorPtr; badString: @@ -322,6 +368,211 @@ TkGetCursorByName( Tcl_AppendResult(interp, "bad cursor spec \"", string, "\"", NULL); return NULL; } + +/* + *---------------------------------------------------------------------- + * + * CreateCursorFromTableOrFile -- + * + * Create a cursor defined in a file or the Tk static cursor table. + * A cursor defined in a file starts with the '@' character. This + * method assumes that the number of arguments in argv has been + * validated already. + * + * Results: + * Returns a new cursor, or None on error. + * + * Side effects: + * Allocates a new X cursor. + * + *---------------------------------------------------------------------- + */ + +Cursor +CreateCursorFromTableOrFile( + Tcl_Interp *interp, /* Interpreter to use for error reporting. */ + Tk_Window tkwin, /* Window in which cursor will be used. */ + int argc, + CONST char **argv, /* Cursor spec parsed into elements. */ + struct TkCursorName *tkCursorPtr) /* Non-NULL when cursor is defined in Tk table */ +{ + Cursor cursor = None; + + int width, height, maskWidth, maskHeight; + int xHot = -1, yHot = -1; + int dummy1, dummy2; + XColor fg, bg; + CONST char *fgColor; + CONST char *bgColor; + int inTkTable = (tkCursorPtr != NULL); + + Display *display = Tk_Display(tkwin); + Drawable drawable = RootWindowOfScreen(Tk_Screen(tkwin)); + + Pixmap source = None; + Pixmap mask = None; + + /* + * A cursor defined in a file accepts either 2 or 4 arguments. + * + * {srcfile fg} + * {srcfile maskfile fg bg} + * + * A cursor defined in the Tk table accepts 1, 2, or 3 arguments. + * + * {tkcursorname} + * {tkcursorname fg} + * {tkcursorname fg bg} + */ + + if (inTkTable) { + /* This logic is like TkReadBitmapFile() */ + char *data; + + data = TkGetBitmapData( + /* interp */ NULL, + /* string */ tkCursorPtr->data, + /* filename */ NULL, + &width, &height, + &xHot, &yHot); + if (data == NULL) { + Tcl_AppendResult(interp, "error reading bitmap data for \"", + argv[0], "\"", NULL); + goto cleanup; + } + + source = XCreateBitmapFromData(display, drawable, + data, width, height); + + ckfree(data); + } else { + if (TkReadBitmapFile(display, drawable, + &argv[0][1], + (unsigned int *) &width, (unsigned int *) &height, + &source, &xHot, &yHot) != BitmapSuccess) { + Tcl_AppendResult(interp, "cleanup reading bitmap file \"", + &argv[0][1], "\"", NULL); + goto cleanup; + } + } + + if ((xHot < 0) || (yHot < 0) || (xHot >= width) || (yHot >= height)) { + if (inTkTable) { + Tcl_AppendResult(interp, "bad hot spot in bitmap data for \"", + argv[0], "\"", NULL); + } else { + Tcl_AppendResult(interp, "bad hot spot in bitmap file \"", + &argv[0][1], "\"", NULL); + } + goto cleanup; + } + + /* + * Parse color names from optional fg and bg arguments + */ + + if (argc == 1) { + fg.red = fg.green = fg.blue = 0; + bg.red = bg.green = bg.blue = 65535; + } else if (argc == 2) { + fgColor = argv[1]; + if (XParseColor(display, Tk_Colormap(tkwin), fgColor, &fg) == 0) { + Tcl_AppendResult(interp, "invalid color name \"", + fgColor, "\"", NULL); + goto cleanup; + } + if (inTkTable) { + bg.red = bg.green = bg.blue = 0; + } else { + bg = fg; + } + } else { + /* 3 or 4 arguments */ + if (inTkTable) { + fgColor = argv[1]; + bgColor = argv[2]; + } else { + fgColor = argv[2]; + bgColor = argv[3]; + } + if (XParseColor(display, Tk_Colormap(tkwin), fgColor, &fg) == 0) { + Tcl_AppendResult(interp, "invalid color name \"", + fgColor, "\"", NULL); + goto cleanup; + } + if (XParseColor(display, Tk_Colormap(tkwin), bgColor, &bg) == 0) { + Tcl_AppendResult(interp, "invalid color name \"", + bgColor, "\"", NULL); + goto cleanup; + } + } + + /* + * If there is no mask data, then create the cursor now. + */ + + if ((!inTkTable && (argc == 2)) || (tkCursorPtr->mask == NULL)) { + cursor = XCreatePixmapCursor(display, source, source, + &fg, &fg, (unsigned) xHot, (unsigned) yHot); + goto cleanup; + } + + /* + * Parse bitmap mask data and create cursor with fg and bg colors. + */ + + if (inTkTable) { + /* This logic is like TkReadBitmapFile() */ + char *data; + + data = TkGetBitmapData( + /* interp */ NULL, + /* string */ tkCursorPtr->mask, + /* filename */ NULL, + &maskWidth, &maskHeight, + &dummy1, &dummy2); + if (data == NULL) { + Tcl_AppendResult(interp, "error reading bitmap mask data for \"", + argv[0], "\"", NULL); + goto cleanup; + } + + mask = XCreateBitmapFromData(display, drawable, + data, maskWidth, maskHeight); + + ckfree(data); + } else { + if (TkReadBitmapFile(display, + drawable, + argv[1], + (unsigned int *) &maskWidth, (unsigned int *) &maskHeight, + &mask, + &dummy1, &dummy2) != BitmapSuccess) { + Tcl_AppendResult(interp, "cleanup reading bitmap file \"", + argv[1], "\"", NULL); + goto cleanup; + } + } + + if ((maskWidth != width) && (maskHeight != height)) { + Tcl_SetResult(interp, + "source and mask bitmaps have different sizes", + TCL_STATIC); + goto cleanup; + } + + cursor = XCreatePixmapCursor(display, source, mask, + &fg, &bg, (unsigned) xHot, (unsigned) yHot); + + cleanup: + if (source != None) { + Tk_FreePixmap(display, source); + } + if (mask != None) { + Tk_FreePixmap(display, mask); + } + return cursor; +} /* *---------------------------------------------------------------------- |