home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / tcl / tk3.3b1 / tkGC.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-16  |  10.7 KB  |  378 lines

  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-1993 The Regents of the University of California.
  8.  * All rights reserved.
  9.  *
  10.  * Permission is hereby granted, without written agreement and without
  11.  * license or royalty fees, to use, copy, modify, and distribute this
  12.  * software and its documentation for any purpose, provided that the
  13.  * above copyright notice and the following two paragraphs appear in
  14.  * all copies of this software.
  15.  * 
  16.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  17.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  18.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  19.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  20.  *
  21.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  22.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  23.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  24.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  25.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  26.  */
  27.  
  28. #ifndef lint
  29. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkGC.c,v 1.12 93/06/16 17:16:16 ouster Exp $ SPRITE (Berkeley)";
  30. #endif /* not lint */
  31.  
  32. #include "tkConfig.h"
  33. #include "tk.h"
  34.  
  35. /*
  36.  * One of the following data structures exists for each GC that is
  37.  * currently active.  The structure is indexed with two hash tables,
  38.  * one based on font name and one based on XFontStruct address.
  39.  */
  40.  
  41. typedef struct {
  42.     GC gc;            /* Graphics context. */
  43.     Display *display;        /* Display to which gc belongs. */
  44.     int refCount;        /* Number of active uses of gc. */
  45.     Tcl_HashEntry *valueHashPtr;/* Entry in valueTable (needed when deleting
  46.                  * this structure). */
  47. } TkGC;
  48.  
  49. /*
  50.  * Hash table to map from a GC's values to a TkGC structure describing
  51.  * a GC with those values (used by Tk_GetGC).
  52.  */
  53.  
  54. static Tcl_HashTable valueTable;
  55. typedef struct {
  56.     XGCValues values;        /* Desired values for GC. */
  57.     Display *display;        /* Display for which GC is valid. */
  58.     int screenNum;        /* screen number of display */
  59.     int depth;            /* and depth for which GC is valid. */
  60. } ValueKey;
  61.  
  62. /*
  63.  * Hash table for <display + GC> -> TkGC mapping. This table is used by
  64.  * Tk_FreeGC.
  65.  */
  66.  
  67. static Tcl_HashTable idTable;
  68. typedef struct {
  69.     Display *display;        /* Display for which GC was allocated. */
  70.     GC gc;            /* X's identifier for GC. */
  71. } IdKey;
  72.  
  73. static int initialized = 0;    /* 0 means static structures haven't been
  74.                  * initialized yet. */
  75.  
  76. /*
  77.  * Forward declarations for procedures defined in this file:
  78.  */
  79.  
  80. static void        GCInit _ANSI_ARGS_((void));
  81.  
  82. /*
  83.  *----------------------------------------------------------------------
  84.  *
  85.  * Tk_GetGC --
  86.  *
  87.  *    Given a desired set of values for a graphics context, find
  88.  *    a read-only graphics context with the desired values.
  89.  *
  90.  * Results:
  91.  *    The return value is the X identifer for the desired graphics
  92.  *    context.  The caller should never modify this GC, and should
  93.  *    call Tk_FreeGC when the GC is no longer needed.
  94.  *
  95.  * Side effects:
  96.  *    The GC is added to an internal database with a reference count.
  97.  *    For each call to this procedure, there should eventually be a call
  98.  *    to Tk_FreeGC, so that the database can be cleaned up when GC's
  99.  *    aren't needed anymore.
  100.  *
  101.  *----------------------------------------------------------------------
  102.  */
  103.  
  104. GC
  105. Tk_GetGC(tkwin, valueMask, valuePtr)
  106.     Tk_Window tkwin;        /* Window in which GC will be used. */
  107.     register unsigned long valueMask;
  108.                 /* 1 bits correspond to values specified
  109.                  * in *valuesPtr;  other values are set
  110.                  * from defaults. */
  111.     register XGCValues *valuePtr;
  112.                 /* Values are specified here for bits set
  113.                  * in valueMask. */
  114. {
  115.     ValueKey valueKey;
  116.     IdKey idKey;
  117.     Tcl_HashEntry *valueHashPtr, *idHashPtr;
  118.     register TkGC *gcPtr;
  119.     int new;
  120.     Drawable d, freeDrawable;
  121.  
  122.     if (!initialized) {
  123.     GCInit();
  124.     }
  125.  
  126.     /*
  127.      * Must zero valueKey at start to clear out pad bytes that may be
  128.      * part of structure on some systems.
  129.      */
  130.  
  131.     memset((VOID *) &valueKey, 0, sizeof(valueKey));
  132.  
  133.     /*
  134.      * First, check to see if there's already a GC that will work
  135.      * for this request (exact matches only, sorry).
  136.      */
  137.  
  138.     if (valueMask & GCFunction) {
  139.     valueKey.values.function = valuePtr->function;
  140.     } else {
  141.     valueKey.values.function = GXcopy;
  142.     }
  143.     if (valueMask & GCPlaneMask) {
  144.     valueKey.values.plane_mask = valuePtr->plane_mask;
  145.     } else {
  146.     valueKey.values.plane_mask = ~0;
  147.     }
  148.     if (valueMask & GCForeground) {
  149.     valueKey.values.foreground = valuePtr->foreground;
  150.     } else {
  151.     valueKey.values.foreground = 0;
  152.     }
  153.     if (valueMask & GCBackground) {
  154.     valueKey.values.background = valuePtr->background;
  155.     } else {
  156.     valueKey.values.background = 1;
  157.     }
  158.     if (valueMask & GCLineWidth) {
  159.     valueKey.values.line_width = valuePtr->line_width;
  160.     } else {
  161.     valueKey.values.line_width = 0;
  162.     }
  163.     if (valueMask & GCLineStyle) {
  164.     valueKey.values.line_style = valuePtr->line_style;
  165.     } else {
  166.     valueKey.values.line_style = LineSolid;
  167.     }
  168.     if (valueMask & GCCapStyle) {
  169.     valueKey.values.cap_style = valuePtr->cap_style;
  170.     } else {
  171.     valueKey.values.cap_style = CapButt;
  172.     }
  173.     if (valueMask & GCJoinStyle) {
  174.     valueKey.values.join_style = valuePtr->join_style;
  175.     } else {
  176.     valueKey.values.join_style = JoinMiter;
  177.     }
  178.     if (valueMask & GCFillStyle) {
  179.     valueKey.values.fill_style = valuePtr->fill_style;
  180.     } else {
  181.     valueKey.values.fill_style = FillSolid;
  182.     }
  183.     if (valueMask & GCFillRule) {
  184.     valueKey.values.fill_rule = valuePtr->fill_rule;
  185.     } else {
  186.     valueKey.values.fill_rule = EvenOddRule;
  187.     }
  188.     if (valueMask & GCArcMode) {
  189.     valueKey.values.arc_mode = valuePtr->arc_mode;
  190.     } else {
  191.     valueKey.values.arc_mode = ArcPieSlice;
  192.     }
  193.     if (valueMask & GCTile) {
  194.     valueKey.values.tile = valuePtr->tile;
  195.     } else {
  196.     valueKey.values.tile = None;
  197.     }
  198.     if (valueMask & GCStipple) {
  199.     valueKey.values.stipple = valuePtr->stipple;
  200.     } else {
  201.     valueKey.values.stipple = None;
  202.     }
  203.     if (valueMask & GCTileStipXOrigin) {
  204.     valueKey.values.ts_x_origin = valuePtr->ts_x_origin;
  205.     } else {
  206.     valueKey.values.ts_x_origin = 0;
  207.     }
  208.     if (valueMask & GCTileStipYOrigin) {
  209.     valueKey.values.ts_y_origin = valuePtr->ts_y_origin;
  210.     } else {
  211.     valueKey.values.ts_y_origin = 0;
  212.     }
  213.     if (valueMask & GCFont) {
  214.     valueKey.values.font = valuePtr->font;
  215.     } else {
  216.     valueKey.values.font = None;
  217.     }
  218.     if (valueMask & GCSubwindowMode) {
  219.     valueKey.values.subwindow_mode = valuePtr->subwindow_mode;
  220.     } else {
  221.     valueKey.values.subwindow_mode = ClipByChildren;
  222.     }
  223.     if (valueMask & GCGraphicsExposures) {
  224.     valueKey.values.graphics_exposures = valuePtr->graphics_exposures;
  225.     } else {
  226.     valueKey.values.graphics_exposures = True;
  227.     }
  228.     if (valueMask & GCClipXOrigin) {
  229.     valueKey.values.clip_x_origin = valuePtr->clip_x_origin;
  230.     } else {
  231.     valueKey.values.clip_x_origin = 0;
  232.     }
  233.     if (valueMask & GCClipYOrigin) {
  234.     valueKey.values.clip_y_origin = valuePtr->clip_y_origin;
  235.     } else {
  236.     valueKey.values.clip_y_origin = 0;
  237.     }
  238.     if (valueMask & GCClipMask) {
  239.     valueKey.values.clip_mask = valuePtr->clip_mask;
  240.     } else {
  241.     valueKey.values.clip_mask = None;
  242.     }
  243.     if (valueMask & GCDashOffset) {
  244.     valueKey.values.dash_offset = valuePtr->dash_offset;
  245.     } else {
  246.     valueKey.values.dash_offset = 0;
  247.     }
  248.     if (valueMask & GCDashList) {
  249.     valueKey.values.dashes = valuePtr->dashes;
  250.     } else {
  251.     valueKey.values.dashes = 4;
  252.     }
  253.     valueKey.display = Tk_Display(tkwin);
  254.     valueKey.screenNum = Tk_ScreenNumber(tkwin);
  255.     valueKey.depth = Tk_Depth(tkwin);
  256.     valueHashPtr = Tcl_CreateHashEntry(&valueTable, (char *) &valueKey, &new);
  257.     if (!new) {
  258.     gcPtr = (TkGC *) Tcl_GetHashValue(valueHashPtr);
  259.     gcPtr->refCount++;
  260.     return gcPtr->gc;
  261.     }
  262.  
  263.     /*
  264.      * No GC is currently available for this set of values.  Allocate a
  265.      * new GC and add a new structure to the database.
  266.      */
  267.  
  268.     gcPtr = (TkGC *) ckalloc(sizeof(TkGC));
  269.  
  270.     /*
  271.      * Find or make a drawable to use to specify the screen and depth
  272.      * of the GC.  We may have to make a small pixmap, to avoid doing
  273.      * Tk_MakeWindowExist on the window.
  274.      */
  275.  
  276.     freeDrawable = None;
  277.     if (Tk_WindowId(tkwin) != None) {
  278.     d = Tk_WindowId(tkwin);
  279.     } else if (valueKey.depth ==
  280.         DefaultDepth(valueKey.display, valueKey.screenNum)) {
  281.     d = RootWindow(valueKey.display, valueKey.screenNum);
  282.     } else {
  283.     d = XCreatePixmap(valueKey.display,
  284.         RootWindow(valueKey.display, valueKey.screenNum),
  285.         1, 1, valueKey.depth);
  286.     freeDrawable = d;
  287.     }
  288.  
  289.     gcPtr->gc = XCreateGC(valueKey.display, d, valueMask, &valueKey.values);
  290.     gcPtr->display = valueKey.display;
  291.     gcPtr->refCount = 1;
  292.     gcPtr->valueHashPtr = valueHashPtr;
  293.     idKey.display = valueKey.display;
  294.     idKey.gc = gcPtr->gc;
  295.     idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, &new);
  296.     if (!new) {
  297.     panic("GC already registered in Tk_GetGC");
  298.     }
  299.     Tcl_SetHashValue(valueHashPtr, gcPtr);
  300.     Tcl_SetHashValue(idHashPtr, gcPtr);
  301.     if (freeDrawable != None) {
  302.     XFreePixmap(valueKey.display, freeDrawable);
  303.     }
  304.  
  305.     return gcPtr->gc;
  306. }
  307.  
  308. /*
  309.  *----------------------------------------------------------------------
  310.  *
  311.  * Tk_FreeGC --
  312.  *
  313.  *    This procedure is called to release a font allocated by
  314.  *    Tk_GetGC.
  315.  *
  316.  * Results:
  317.  *    None.
  318.  *
  319.  * Side effects:
  320.  *    The reference count associated with gc is decremented, and
  321.  *    gc is officially deallocated if no-one is using it anymore.
  322.  *
  323.  *----------------------------------------------------------------------
  324.  */
  325.  
  326. void
  327. Tk_FreeGC(display, gc)
  328.     Display *display;        /* Display for which gc was allocated. */
  329.     GC gc;            /* Graphics context to be released. */
  330. {
  331.     IdKey idKey;
  332.     Tcl_HashEntry *idHashPtr;
  333.     register TkGC *gcPtr;
  334.  
  335.     if (!initialized) {
  336.     panic("Tk_FreeGC called before Tk_GetGC");
  337.     }
  338.  
  339.     idKey.display = display;
  340.     idKey.gc = gc;
  341.     idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey);
  342.     if (idHashPtr == NULL) {
  343.     panic("Tk_FreeGC received unknown gc argument");
  344.     }
  345.     gcPtr = (TkGC *) Tcl_GetHashValue(idHashPtr);
  346.     gcPtr->refCount--;
  347.     if (gcPtr->refCount == 0) {
  348.     XFreeGC(gcPtr->display, gcPtr->gc);
  349.     Tcl_DeleteHashEntry(gcPtr->valueHashPtr);
  350.     Tcl_DeleteHashEntry(idHashPtr);
  351.     ckfree((char *) gcPtr);
  352.     }
  353. }
  354.  
  355. /*
  356.  *----------------------------------------------------------------------
  357.  *
  358.  * GCInit --
  359.  *
  360.  *    Initialize the structures used for GC management.
  361.  *
  362.  * Results:
  363.  *    None.
  364.  *
  365.  * Side effects:
  366.  *    Read the code.
  367.  *
  368.  *----------------------------------------------------------------------
  369.  */
  370.  
  371. static void
  372. GCInit()
  373. {
  374.     initialized = 1;
  375.     Tcl_InitHashTable(&valueTable, sizeof(ValueKey)/sizeof(int));
  376.     Tcl_InitHashTable(&idTable, sizeof(IdKey)/sizeof(int));
  377. }
  378.