tkGC.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:11k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkGC.c --
  3.  *
  4.  * This file maintains a database of read-only graphics contexts 
  5.  * for the Tk toolkit, in order to allow GC's to be shared.
  6.  *
  7.  * Copyright (c) 1990-1994 The Regents of the University of California.
  8.  * Copyright (c) 1994 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * RCS: @(#) $Id: tkGC.c,v 1.4 2002/04/12 10:02:40 hobbs Exp $
  14.  */
  15. #include "tkPort.h"
  16. #include "tkInt.h"
  17. /*
  18.  * One of the following data structures exists for each GC that is
  19.  * currently active.  The structure is indexed with two hash tables,
  20.  * one based on the values in the graphics context and the other
  21.  * based on the display and GC identifier.
  22.  */
  23. typedef struct {
  24.     GC gc; /* Graphics context. */
  25.     Display *display; /* Display to which gc belongs. */
  26.     int refCount; /* Number of active uses of gc. */
  27.     Tcl_HashEntry *valueHashPtr;/* Entry in valueTable (needed when deleting
  28.  * this structure). */
  29. } TkGC;
  30. typedef struct {
  31.     XGCValues values; /* Desired values for GC. */
  32.     Display *display; /* Display for which GC is valid. */
  33.     int screenNum; /* screen number of display */
  34.     int depth; /* and depth for which GC is valid. */
  35. } ValueKey;
  36. /*
  37.  * Forward declarations for procedures defined in this file:
  38.  */
  39. static void GCInit _ANSI_ARGS_((TkDisplay *dispPtr));
  40. /*
  41.  *----------------------------------------------------------------------
  42.  *
  43.  * Tk_GetGC --
  44.  *
  45.  * Given a desired set of values for a graphics context, find
  46.  * a read-only graphics context with the desired values.
  47.  *
  48.  * Results:
  49.  * The return value is the X identifer for the desired graphics
  50.  * context.  The caller should never modify this GC, and should
  51.  * call Tk_FreeGC when the GC is no longer needed.
  52.  *
  53.  * Side effects:
  54.  * The GC is added to an internal database with a reference count.
  55.  * For each call to this procedure, there should eventually be a call
  56.  * to Tk_FreeGC, so that the database can be cleaned up when GC's
  57.  * aren't needed anymore.
  58.  *
  59.  *----------------------------------------------------------------------
  60.  */
  61. GC
  62. Tk_GetGC(tkwin, valueMask, valuePtr)
  63.     Tk_Window tkwin; /* Window in which GC will be used. */
  64.     register unsigned long valueMask;
  65. /* 1 bits correspond to values specified
  66.  * in *valuesPtr;  other values are set
  67.  * from defaults. */
  68.     register XGCValues *valuePtr;
  69. /* Values are specified here for bits set
  70.  * in valueMask. */
  71. {
  72.     ValueKey valueKey;
  73.     Tcl_HashEntry *valueHashPtr, *idHashPtr;
  74.     register TkGC *gcPtr;
  75.     int new;
  76.     Drawable d, freeDrawable;
  77.     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  78.     if (dispPtr->gcInit <= 0) {
  79. GCInit(dispPtr);
  80.     }
  81.     /*
  82.      * Must zero valueKey at start to clear out pad bytes that may be
  83.      * part of structure on some systems.
  84.      */
  85.     memset((VOID *) &valueKey, 0, sizeof(valueKey));
  86.     /*
  87.      * First, check to see if there's already a GC that will work
  88.      * for this request (exact matches only, sorry).
  89.      */
  90.     if (valueMask & GCFunction) {
  91. valueKey.values.function = valuePtr->function;
  92.     } else {
  93. valueKey.values.function = GXcopy;
  94.     }
  95.     if (valueMask & GCPlaneMask) {
  96. valueKey.values.plane_mask = valuePtr->plane_mask;
  97.     } else {
  98. valueKey.values.plane_mask = (unsigned) ~0;
  99.     }
  100.     if (valueMask & GCForeground) {
  101. valueKey.values.foreground = valuePtr->foreground;
  102.     } else {
  103. valueKey.values.foreground = 0;
  104.     }
  105.     if (valueMask & GCBackground) {
  106. valueKey.values.background = valuePtr->background;
  107.     } else {
  108. valueKey.values.background = 1;
  109.     }
  110.     if (valueMask & GCLineWidth) {
  111. valueKey.values.line_width = valuePtr->line_width;
  112.     } else {
  113. valueKey.values.line_width = 0;
  114.     }
  115.     if (valueMask & GCLineStyle) {
  116. valueKey.values.line_style = valuePtr->line_style;
  117.     } else {
  118. valueKey.values.line_style = LineSolid;
  119.     }
  120.     if (valueMask & GCCapStyle) {
  121. valueKey.values.cap_style = valuePtr->cap_style;
  122.     } else {
  123. valueKey.values.cap_style = CapButt;
  124.     }
  125.     if (valueMask & GCJoinStyle) {
  126. valueKey.values.join_style = valuePtr->join_style;
  127.     } else {
  128. valueKey.values.join_style = JoinMiter;
  129.     }
  130.     if (valueMask & GCFillStyle) {
  131. valueKey.values.fill_style = valuePtr->fill_style;
  132.     } else {
  133. valueKey.values.fill_style = FillSolid;
  134.     }
  135.     if (valueMask & GCFillRule) {
  136. valueKey.values.fill_rule = valuePtr->fill_rule;
  137.     } else {
  138. valueKey.values.fill_rule = EvenOddRule;
  139.     }
  140.     if (valueMask & GCArcMode) {
  141. valueKey.values.arc_mode = valuePtr->arc_mode;
  142.     } else {
  143. valueKey.values.arc_mode = ArcPieSlice;
  144.     }
  145.     if (valueMask & GCTile) {
  146. valueKey.values.tile = valuePtr->tile;
  147.     } else {
  148. valueKey.values.tile = None;
  149.     }
  150.     if (valueMask & GCStipple) {
  151. valueKey.values.stipple = valuePtr->stipple;
  152.     } else {
  153. valueKey.values.stipple = None;
  154.     }
  155.     if (valueMask & GCTileStipXOrigin) {
  156. valueKey.values.ts_x_origin = valuePtr->ts_x_origin;
  157.     } else {
  158. valueKey.values.ts_x_origin = 0;
  159.     }
  160.     if (valueMask & GCTileStipYOrigin) {
  161. valueKey.values.ts_y_origin = valuePtr->ts_y_origin;
  162.     } else {
  163. valueKey.values.ts_y_origin = 0;
  164.     }
  165.     if (valueMask & GCFont) {
  166. valueKey.values.font = valuePtr->font;
  167.     } else {
  168. valueKey.values.font = None;
  169.     }
  170.     if (valueMask & GCSubwindowMode) {
  171. valueKey.values.subwindow_mode = valuePtr->subwindow_mode;
  172.     } else {
  173. valueKey.values.subwindow_mode = ClipByChildren;
  174.     }
  175.     if (valueMask & GCGraphicsExposures) {
  176. valueKey.values.graphics_exposures = valuePtr->graphics_exposures;
  177.     } else {
  178. valueKey.values.graphics_exposures = True;
  179.     }
  180.     if (valueMask & GCClipXOrigin) {
  181. valueKey.values.clip_x_origin = valuePtr->clip_x_origin;
  182.     } else {
  183. valueKey.values.clip_x_origin = 0;
  184.     }
  185.     if (valueMask & GCClipYOrigin) {
  186. valueKey.values.clip_y_origin = valuePtr->clip_y_origin;
  187.     } else {
  188. valueKey.values.clip_y_origin = 0;
  189.     }
  190.     if (valueMask & GCClipMask) {
  191. valueKey.values.clip_mask = valuePtr->clip_mask;
  192.     } else {
  193. valueKey.values.clip_mask = None;
  194.     }
  195.     if (valueMask & GCDashOffset) {
  196. valueKey.values.dash_offset = valuePtr->dash_offset;
  197.     } else {
  198. valueKey.values.dash_offset = 0;
  199.     }
  200.     if (valueMask & GCDashList) {
  201. valueKey.values.dashes = valuePtr->dashes;
  202.     } else {
  203. valueKey.values.dashes = 4;
  204.     }
  205.     valueKey.display = Tk_Display(tkwin);
  206.     valueKey.screenNum = Tk_ScreenNumber(tkwin);
  207.     valueKey.depth = Tk_Depth(tkwin);
  208.     valueHashPtr = Tcl_CreateHashEntry(&dispPtr->gcValueTable, 
  209.             (char *) &valueKey, &new);
  210.     if (!new) {
  211. gcPtr = (TkGC *) Tcl_GetHashValue(valueHashPtr);
  212. gcPtr->refCount++;
  213. return gcPtr->gc;
  214.     }
  215.     /*
  216.      * No GC is currently available for this set of values.  Allocate a
  217.      * new GC and add a new structure to the database.
  218.      */
  219.     gcPtr = (TkGC *) ckalloc(sizeof(TkGC));
  220.     /*
  221.      * Find or make a drawable to use to specify the screen and depth
  222.      * of the GC.  We may have to make a small pixmap, to avoid doing
  223.      * Tk_MakeWindowExist on the window.
  224.      */
  225.     freeDrawable = None;
  226.     if (Tk_WindowId(tkwin) != None) {
  227. d = Tk_WindowId(tkwin);
  228.     } else if (valueKey.depth ==
  229.     DefaultDepth(valueKey.display, valueKey.screenNum)) {
  230. d = RootWindow(valueKey.display, valueKey.screenNum);
  231.     } else {
  232. d = Tk_GetPixmap(valueKey.display,
  233. RootWindow(valueKey.display, valueKey.screenNum),
  234. 1, 1, valueKey.depth);
  235. freeDrawable = d;
  236.     }
  237.     gcPtr->gc = XCreateGC(valueKey.display, d, valueMask, &valueKey.values);
  238.     gcPtr->display = valueKey.display;
  239.     gcPtr->refCount = 1;
  240.     gcPtr->valueHashPtr = valueHashPtr;
  241.     idHashPtr = Tcl_CreateHashEntry(&dispPtr->gcIdTable, 
  242.             (char *) gcPtr->gc, &new);
  243.     if (!new) {
  244. panic("GC already registered in Tk_GetGC");
  245.     }
  246.     Tcl_SetHashValue(valueHashPtr, gcPtr);
  247.     Tcl_SetHashValue(idHashPtr, gcPtr);
  248.     if (freeDrawable != None) {
  249. Tk_FreePixmap(valueKey.display, freeDrawable);
  250.     }
  251.     return gcPtr->gc;
  252. }
  253. /*
  254.  *----------------------------------------------------------------------
  255.  *
  256.  * Tk_FreeGC --
  257.  *
  258.  * This procedure is called to release a graphics context allocated by
  259.  * Tk_GetGC.
  260.  *
  261.  * Results:
  262.  * None.
  263.  *
  264.  * Side effects:
  265.  * The reference count associated with gc is decremented, and
  266.  * gc is officially deallocated if no-one is using it anymore.
  267.  *
  268.  *----------------------------------------------------------------------
  269.  */
  270. void
  271. Tk_FreeGC(display, gc)
  272.     Display *display; /* Display for which gc was allocated. */
  273.     GC gc; /* Graphics context to be released. */
  274. {
  275.     Tcl_HashEntry *idHashPtr;
  276.     register TkGC *gcPtr;
  277.     TkDisplay *dispPtr = TkGetDisplay(display);
  278.     if (!dispPtr->gcInit) {
  279. panic("Tk_FreeGC called before Tk_GetGC");
  280.     }
  281.     if (dispPtr->gcInit < 0) {
  282. /*
  283.  * The GCCleanup has been called, and remaining GCs have been
  284.  * freed.  This may still get called by other things shutting
  285.  * down, but the GCs should no longer be in use.
  286.  */
  287. return;
  288.     }
  289.     idHashPtr = Tcl_FindHashEntry(&dispPtr->gcIdTable, (char *) gc);
  290.     if (idHashPtr == NULL) {
  291. panic("Tk_FreeGC received unknown gc argument");
  292.     }
  293.     gcPtr = (TkGC *) Tcl_GetHashValue(idHashPtr);
  294.     gcPtr->refCount--;
  295.     if (gcPtr->refCount == 0) {
  296. Tk_FreeXId(gcPtr->display, (XID) XGContextFromGC(gcPtr->gc));
  297. XFreeGC(gcPtr->display, gcPtr->gc);
  298. Tcl_DeleteHashEntry(gcPtr->valueHashPtr);
  299. Tcl_DeleteHashEntry(idHashPtr);
  300. ckfree((char *) gcPtr);
  301.     }
  302. }
  303. /*
  304.  *----------------------------------------------------------------------
  305.  *
  306.  * TkGCCleanup --
  307.  *
  308.  * Frees the structures used for GC management.
  309.  * We need to have it called near the end, when other cleanup that
  310.  * calls Tk_FreeGC is all done.
  311.  *
  312.  * Results:
  313.  * None.
  314.  *
  315.  * Side effects:
  316.  * GC resources are freed.
  317.  *
  318.  *----------------------------------------------------------------------
  319.  */
  320. void
  321. TkGCCleanup(dispPtr)
  322.     TkDisplay *dispPtr; /* display to clean up resources in */
  323. {
  324.     Tcl_HashEntry *entryPtr;
  325.     Tcl_HashSearch search;
  326.     TkGC *gcPtr;
  327.     for (entryPtr = Tcl_FirstHashEntry(&dispPtr->gcIdTable, &search);
  328.  entryPtr != NULL;
  329.  entryPtr = Tcl_NextHashEntry(&search)) {
  330. gcPtr = (TkGC *) Tcl_GetHashValue(entryPtr);
  331. /*
  332.  * This call is not needed, as it is only used on Unix to restore
  333.  * the Id to the stack pool, and we don't want to use them anymore.
  334.  *   Tk_FreeXId(gcPtr->display, (XID) XGContextFromGC(gcPtr->gc));
  335.  */
  336. XFreeGC(gcPtr->display, gcPtr->gc);
  337. Tcl_DeleteHashEntry(gcPtr->valueHashPtr);
  338. Tcl_DeleteHashEntry(entryPtr);
  339. ckfree((char *) gcPtr);
  340.     }
  341.     Tcl_DeleteHashTable(&dispPtr->gcValueTable);
  342.     Tcl_DeleteHashTable(&dispPtr->gcIdTable);
  343.     dispPtr->gcInit = -1;
  344. }
  345. /*
  346.  *----------------------------------------------------------------------
  347.  *
  348.  * GCInit --
  349.  *
  350.  * Initialize the structures used for GC management.
  351.  *
  352.  * Results:
  353.  * None.
  354.  *
  355.  * Side effects:
  356.  * Read the code.
  357.  *
  358.  *----------------------------------------------------------------------
  359.  */
  360. static void
  361. GCInit(dispPtr)
  362.     TkDisplay *dispPtr;
  363. {
  364.     if (dispPtr->gcInit < 0) {
  365. panic("called GCInit after GCCleanup");
  366.     }
  367.     dispPtr->gcInit = 1;
  368.     Tcl_InitHashTable(&dispPtr->gcValueTable, sizeof(ValueKey)/sizeof(int));
  369.     Tcl_InitHashTable(&dispPtr->gcIdTable, TCL_ONE_WORD_KEYS);
  370. }