summaryrefslogtreecommitdiffstats
path: root/generic/tkCursor.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tkCursor.c')
-rw-r--r--generic/tkCursor.c384
1 files changed, 384 insertions, 0 deletions
diff --git a/generic/tkCursor.c b/generic/tkCursor.c
new file mode 100644
index 0000000..e185109
--- /dev/null
+++ b/generic/tkCursor.c
@@ -0,0 +1,384 @@
+/*
+ * tkCursor.c --
+ *
+ * This file maintains a database of read-only cursors for the Tk
+ * toolkit. This allows cursors to be shared between widgets and
+ * also avoids round-trips to the X server.
+ *
+ * Copyright (c) 1990-1994 The Regents of the University of California.
+ * Copyright (c) 1994-1995 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * SCCS: @(#) tkCursor.c 1.27 96/02/15 18:52:40
+ */
+
+#include "tkPort.h"
+#include "tkInt.h"
+
+/*
+ * A TkCursor structure exists for each cursor that is currently
+ * active. Each structure is indexed with two hash tables defined
+ * below. One of the tables is idTable, and the other is either
+ * nameTable or dataTable, also defined below.
+ */
+
+/*
+ * Hash table to map from a textual description of a cursor to the
+ * TkCursor record for the cursor, and key structure used in that
+ * hash table:
+ */
+
+static Tcl_HashTable nameTable;
+typedef struct {
+ Tk_Uid name; /* Textual name for desired cursor. */
+ Display *display; /* Display for which cursor will be used. */
+} NameKey;
+
+/*
+ * Hash table to map from a collection of in-core data about a
+ * cursor (bitmap contents, etc.) to a TkCursor structure:
+ */
+
+static Tcl_HashTable dataTable;
+typedef struct {
+ char *source; /* Cursor bits. */
+ char *mask; /* Mask bits. */
+ int width, height; /* Dimensions of cursor (and data
+ * and mask). */
+ int xHot, yHot; /* Location of cursor hot-spot. */
+ Tk_Uid fg, bg; /* Colors for cursor. */
+ Display *display; /* Display on which cursor will be used. */
+} DataKey;
+
+/*
+ * Hash table that maps from <display + cursor id> to the TkCursor structure
+ * for the cursor. This table is used by Tk_FreeCursor.
+ */
+
+static Tcl_HashTable idTable;
+typedef struct {
+ Display *display; /* Display for which cursor was allocated. */
+ Tk_Cursor cursor; /* Cursor identifier. */
+} IdKey;
+
+static int initialized = 0; /* 0 means static structures haven't been
+ * initialized yet. */
+
+/*
+ * Forward declarations for procedures defined in this file:
+ */
+
+static void CursorInit _ANSI_ARGS_((void));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tk_GetCursor --
+ *
+ * Given a string describing a cursor, locate (or create if necessary)
+ * a cursor that fits the description.
+ *
+ * Results:
+ * The return value is the X identifer for the desired cursor,
+ * unless string couldn't be parsed correctly. In this case,
+ * None is returned and an error message is left in interp->result.
+ * The caller should never modify the cursor that is returned, and
+ * should eventually call Tk_FreeCursor when the cursor is no longer
+ * needed.
+ *
+ * Side effects:
+ * The cursor is added to an internal database with a reference count.
+ * For each call to this procedure, there should eventually be a call
+ * to Tk_FreeCursor, so that the database can be cleaned up when cursors
+ * aren't needed anymore.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tk_Cursor
+Tk_GetCursor(interp, tkwin, string)
+ Tcl_Interp *interp; /* Interpreter to use for error reporting. */
+ Tk_Window tkwin; /* Window in which cursor will be used. */
+ Tk_Uid string; /* Description of cursor. See manual entry
+ * for details on legal syntax. */
+{
+ NameKey nameKey;
+ IdKey idKey;
+ Tcl_HashEntry *nameHashPtr, *idHashPtr;
+ register TkCursor *cursorPtr;
+ int new;
+
+ if (!initialized) {
+ CursorInit();
+ }
+
+ nameKey.name = string;
+ nameKey.display = Tk_Display(tkwin);
+ nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &nameKey, &new);
+ if (!new) {
+ cursorPtr = (TkCursor *) Tcl_GetHashValue(nameHashPtr);
+ cursorPtr->refCount++;
+ return cursorPtr->cursor;
+ }
+
+ cursorPtr = TkGetCursorByName(interp, tkwin, string);
+
+ if (cursorPtr == NULL) {
+ Tcl_DeleteHashEntry(nameHashPtr);
+ return None;
+ }
+
+ /*
+ * Add information about this cursor to our database.
+ */
+
+ cursorPtr->refCount = 1;
+ cursorPtr->otherTable = &nameTable;
+ cursorPtr->hashPtr = nameHashPtr;
+ idKey.display = nameKey.display;
+ idKey.cursor = cursorPtr->cursor;
+ idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, &new);
+ if (!new) {
+ panic("cursor already registered in Tk_GetCursor");
+ }
+ Tcl_SetHashValue(nameHashPtr, cursorPtr);
+ Tcl_SetHashValue(idHashPtr, cursorPtr);
+
+ return cursorPtr->cursor;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tk_GetCursorFromData --
+ *
+ * Given a description of the bits and colors for a cursor,
+ * make a cursor that has the given properties.
+ *
+ * Results:
+ * The return value is the X identifer for the desired cursor,
+ * unless it couldn't be created properly. In this case, None is
+ * returned and an error message is left in interp->result. The
+ * caller should never modify the cursor that is returned, and
+ * should eventually call Tk_FreeCursor when the cursor is no
+ * longer needed.
+ *
+ * Side effects:
+ * The cursor is added to an internal database with a reference count.
+ * For each call to this procedure, there should eventually be a call
+ * to Tk_FreeCursor, so that the database can be cleaned up when cursors
+ * aren't needed anymore.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tk_Cursor
+Tk_GetCursorFromData(interp, tkwin, source, mask, width, height,
+ xHot, yHot, fg, bg)
+ Tcl_Interp *interp; /* Interpreter to use for error reporting. */
+ Tk_Window tkwin; /* Window in which cursor will be used. */
+ char *source; /* Bitmap data for cursor shape. */
+ char *mask; /* Bitmap data for cursor mask. */
+ int width, height; /* Dimensions of cursor. */
+ int xHot, yHot; /* Location of hot-spot in cursor. */
+ Tk_Uid fg; /* Foreground color for cursor. */
+ Tk_Uid bg; /* Background color for cursor. */
+{
+ DataKey dataKey;
+ IdKey idKey;
+ Tcl_HashEntry *dataHashPtr, *idHashPtr;
+ register TkCursor *cursorPtr;
+ int new;
+ XColor fgColor, bgColor;
+
+ if (!initialized) {
+ CursorInit();
+ }
+
+ dataKey.source = source;
+ dataKey.mask = mask;
+ dataKey.width = width;
+ dataKey.height = height;
+ dataKey.xHot = xHot;
+ dataKey.yHot = yHot;
+ dataKey.fg = fg;
+ dataKey.bg = bg;
+ dataKey.display = Tk_Display(tkwin);
+ dataHashPtr = Tcl_CreateHashEntry(&dataTable, (char *) &dataKey, &new);
+ if (!new) {
+ cursorPtr = (TkCursor *) Tcl_GetHashValue(dataHashPtr);
+ cursorPtr->refCount++;
+ return cursorPtr->cursor;
+ }
+
+ /*
+ * No suitable cursor exists yet. Make one using the data
+ * available and add it to the database.
+ */
+
+ if (XParseColor(dataKey.display, Tk_Colormap(tkwin), fg, &fgColor) == 0) {
+ Tcl_AppendResult(interp, "invalid color name \"", fg, "\"",
+ (char *) NULL);
+ goto error;
+ }
+ if (XParseColor(dataKey.display, Tk_Colormap(tkwin), bg, &bgColor) == 0) {
+ Tcl_AppendResult(interp, "invalid color name \"", bg, "\"",
+ (char *) NULL);
+ goto error;
+ }
+
+ cursorPtr = TkCreateCursorFromData(tkwin, source, mask, width, height,
+ xHot, yHot, fgColor, bgColor);
+
+ if (cursorPtr == NULL) {
+ goto error;
+ }
+
+ cursorPtr->refCount = 1;
+ cursorPtr->otherTable = &dataTable;
+ cursorPtr->hashPtr = dataHashPtr;
+ idKey.display = dataKey.display;
+ idKey.cursor = cursorPtr->cursor;
+ idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, &new);
+ if (!new) {
+ panic("cursor already registered in Tk_GetCursorFromData");
+ }
+ Tcl_SetHashValue(dataHashPtr, cursorPtr);
+ Tcl_SetHashValue(idHashPtr, cursorPtr);
+ return cursorPtr->cursor;
+
+ error:
+ Tcl_DeleteHashEntry(dataHashPtr);
+ return None;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Tk_NameOfCursor --
+ *
+ * Given a cursor, return a textual string identifying it.
+ *
+ * Results:
+ * If cursor was created by Tk_GetCursor, then the return
+ * value is the "string" that was used to create it.
+ * Otherwise the return value is a string giving the X
+ * identifier for the cursor. The storage for the returned
+ * string is only guaranteed to persist up until the next
+ * call to this procedure.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+char *
+Tk_NameOfCursor(display, cursor)
+ Display *display; /* Display for which cursor was allocated. */
+ Tk_Cursor cursor; /* Identifier for cursor whose name is
+ * wanted. */
+{
+ IdKey idKey;
+ Tcl_HashEntry *idHashPtr;
+ TkCursor *cursorPtr;
+ static char string[20];
+
+ if (!initialized) {
+ printid:
+ sprintf(string, "cursor id 0x%x", (unsigned int) cursor);
+ return string;
+ }
+ idKey.display = display;
+ idKey.cursor = cursor;
+ idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey);
+ if (idHashPtr == NULL) {
+ goto printid;
+ }
+ cursorPtr = (TkCursor *) Tcl_GetHashValue(idHashPtr);
+ if (cursorPtr->otherTable != &nameTable) {
+ goto printid;
+ }
+ return ((NameKey *) cursorPtr->hashPtr->key.words)->name;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tk_FreeCursor --
+ *
+ * This procedure is called to release a cursor allocated by
+ * Tk_GetCursor or TkGetCursorFromData.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The reference count associated with cursor is decremented, and
+ * it is officially deallocated if no-one is using it anymore.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tk_FreeCursor(display, cursor)
+ Display *display; /* Display for which cursor was allocated. */
+ Tk_Cursor cursor; /* Identifier for cursor to be released. */
+{
+ IdKey idKey;
+ Tcl_HashEntry *idHashPtr;
+ register TkCursor *cursorPtr;
+
+ if (!initialized) {
+ panic("Tk_FreeCursor called before Tk_GetCursor");
+ }
+
+ idKey.display = display;
+ idKey.cursor = cursor;
+ idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey);
+ if (idHashPtr == NULL) {
+ panic("Tk_FreeCursor received unknown cursor argument");
+ }
+ cursorPtr = (TkCursor *) Tcl_GetHashValue(idHashPtr);
+ cursorPtr->refCount--;
+ if (cursorPtr->refCount == 0) {
+ Tcl_DeleteHashEntry(cursorPtr->hashPtr);
+ Tcl_DeleteHashEntry(idHashPtr);
+ TkFreeCursor(cursorPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CursorInit --
+ *
+ * Initialize the structures used for cursor management.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Read the code.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+CursorInit()
+{
+ initialized = 1;
+ Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int));
+ Tcl_InitHashTable(&dataTable, sizeof(DataKey)/sizeof(int));
+
+ /*
+ * The call below is tricky: can't use sizeof(IdKey) because it
+ * gets padded with extra unpredictable bytes on some 64-bit
+ * machines.
+ */
+
+ Tcl_InitHashTable(&idTable, (sizeof(Display *) + sizeof(Tk_Cursor))
+ /sizeof(int));
+}